2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/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 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
179 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
180 *PointerPte
= TempPte
;
187 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
189 /* Now unmap the view */
190 Status
= MmUnmapViewOfSection(Process
, Base
);
191 ASSERT(NT_SUCCESS(Status
));
193 /* Detach and return status */
194 KeUnstackDetachProcess(&ApcState
);
200 MiLocateExportName(IN PVOID DllBase
,
204 PUSHORT OrdinalTable
;
205 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
206 LONG Low
= 0, Mid
= 0, High
, Ret
;
213 /* Get the export directory */
214 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
216 IMAGE_DIRECTORY_ENTRY_EXPORT
,
218 if (!ExportDirectory
) return NULL
;
220 /* Setup name tables */
221 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
222 ExportDirectory
->AddressOfNames
);
223 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
224 ExportDirectory
->AddressOfNameOrdinals
);
226 /* Do a binary search */
227 High
= ExportDirectory
->NumberOfNames
- 1;
230 /* Get new middle value */
231 Mid
= (Low
+ High
) >> 1;
234 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
252 /* Check if we couldn't find it */
253 if (High
< Low
) return NULL
;
255 /* Otherwise, this is the ordinal */
256 Ordinal
= OrdinalTable
[Mid
];
258 /* Resolve the address and write it */
259 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
260 ExportDirectory
->AddressOfFunctions
);
261 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
263 /* Check if the function is actually a forwarder */
264 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
265 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
277 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
278 IN PLIST_ENTRY ListHead
)
280 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
281 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
282 PMM_DLL_INITIALIZE DllInit
;
283 UNICODE_STRING RegPath
, ImportName
;
286 /* Try to see if the image exports a DllInitialize routine */
287 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
289 if (!DllInit
) return STATUS_SUCCESS
;
291 /* Do a temporary copy of BaseDllName called ImportName
292 * because we'll alter the length of the string
294 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
295 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
296 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
298 /* Obtain the path to this dll's service in the registry */
299 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
300 ImportName
.Length
+ sizeof(UNICODE_NULL
);
301 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
302 RegPath
.MaximumLength
,
305 /* Check if this allocation was unsuccessful */
306 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
308 /* Build and append the service name itself */
309 RegPath
.Length
= ServicesKeyName
.Length
;
310 RtlCopyMemory(RegPath
.Buffer
,
311 ServicesKeyName
.Buffer
,
312 ServicesKeyName
.Length
);
314 /* Check if there is a dot in the filename */
315 if (wcschr(ImportName
.Buffer
, L
'.'))
317 /* Remove the extension */
318 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
319 ImportName
.Buffer
) * sizeof(WCHAR
);
322 /* Append service name (the basename without extension) */
323 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
325 /* Now call the DllInit func */
326 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
327 Status
= DllInit(&RegPath
);
330 ExFreePool(RegPath
.Buffer
);
332 /* Return status value which DllInitialize returned */
338 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
344 /* Get the unload routine */
345 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
346 if (!Func
) return FALSE
;
348 /* Call it and check for success */
350 if (!NT_SUCCESS(Status
)) return FALSE
;
352 /* Lie about the load count so we can unload the image */
353 ASSERT(LdrEntry
->LoadCount
== 0);
354 LdrEntry
->LoadCount
= 1;
356 /* Unload it and return true */
357 MmUnloadSystemImage(LdrEntry
);
363 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
366 LOAD_IMPORTS SingleEntry
;
367 PLDR_DATA_TABLE_ENTRY LdrEntry
;
368 PVOID CurrentImports
;
371 /* Check if there's no imports or if we're a boot driver */
372 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
373 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
374 (ImportList
->Count
== 0))
376 /* Then there's nothing to do */
377 return STATUS_SUCCESS
;
380 /* Check for single-entry */
381 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
384 SingleEntry
.Count
= 1;
385 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
387 /* Use this as the import list */
388 ImportList
= &SingleEntry
;
391 /* Loop the import list */
392 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
395 LdrEntry
= ImportList
->Entry
[i
];
396 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
398 /* Skip boot loaded images */
399 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
401 /* Dereference the entry */
402 ASSERT(LdrEntry
->LoadCount
>= 1);
403 if (!--LdrEntry
->LoadCount
)
405 /* Save the import data in case unload fails */
406 CurrentImports
= LdrEntry
->LoadedImports
;
408 /* This is the last entry */
409 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
410 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
412 /* Unloading worked, parse this DLL's imports too */
413 MiDereferenceImports(CurrentImports
);
415 /* Check if we had valid imports */
416 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
417 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
418 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
421 ExFreePool(CurrentImports
);
426 /* Unload failed, restore imports */
427 LdrEntry
->LoadedImports
= CurrentImports
;
433 return STATUS_SUCCESS
;
438 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
442 /* Check if there's no imports or we're a boot driver or only one entry */
443 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
444 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
445 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
451 /* Otherwise, free the import list */
452 ExFreePool(LdrEntry
->LoadedImports
);
453 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
458 MiFindExportedRoutineByName(IN PVOID DllBase
,
459 IN PANSI_STRING ExportName
)
462 PUSHORT OrdinalTable
;
463 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
464 LONG Low
= 0, Mid
= 0, High
, Ret
;
471 /* Get the export directory */
472 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
474 IMAGE_DIRECTORY_ENTRY_EXPORT
,
476 if (!ExportDirectory
) return NULL
;
478 /* Setup name tables */
479 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
480 ExportDirectory
->AddressOfNames
);
481 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
482 ExportDirectory
->AddressOfNameOrdinals
);
484 /* Do a binary search */
485 High
= ExportDirectory
->NumberOfNames
- 1;
488 /* Get new middle value */
489 Mid
= (Low
+ High
) >> 1;
492 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
510 /* Check if we couldn't find it */
511 if (High
< Low
) return NULL
;
513 /* Otherwise, this is the ordinal */
514 Ordinal
= OrdinalTable
[Mid
];
516 /* Validate the ordinal */
517 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
519 /* Resolve the address and write it */
520 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
521 ExportDirectory
->AddressOfFunctions
);
522 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
525 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
526 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
532 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
537 /* Acquire module list lock */
538 KeEnterCriticalRegion();
539 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
541 /* Acquire the spinlock too as we will insert or remove the entry */
542 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
544 /* Insert or remove from the list */
545 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
546 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
549 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
550 ExReleaseResourceLite(&PsLoadedModuleResource
);
551 KeLeaveCriticalRegion();
556 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
561 ULONG_PTR OldBaseTop
, Delta
;
562 PLDR_DATA_TABLE_ENTRY LdrEntry
;
563 PLIST_ENTRY NextEntry
;
565 PULONG_PTR ImageThunk
;
566 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
568 /* Calculate the top and delta */
569 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
570 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
572 /* Loop the loader block */
573 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
574 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
575 NextEntry
= NextEntry
->Flink
)
577 /* Get the loader entry */
578 LdrEntry
= CONTAINING_RECORD(NextEntry
,
579 LDR_DATA_TABLE_ENTRY
,
581 #ifdef _WORKING_LINKER_
583 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
585 IMAGE_DIRECTORY_ENTRY_IAT
,
587 if (!ImageThunk
) continue;
589 /* Make sure we have an IAT */
590 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
591 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
593 /* Check if it's within this module */
594 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
597 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
598 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
599 *ImageThunk
+= Delta
;
603 /* Get the import table */
605 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
607 IMAGE_DIRECTORY_ENTRY_IMPORT
,
609 if (!ImportDescriptor
) continue;
611 /* Make sure we have an IAT */
612 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
613 while ((ImportDescriptor
->Name
) &&
614 (ImportDescriptor
->OriginalFirstThunk
))
616 /* Get the image thunk */
617 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
618 ImportDescriptor
->FirstThunk
);
621 /* Check if it's within this module */
622 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
625 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
626 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
627 *ImageThunk
+= Delta
;
630 /* Go to the next thunk */
634 /* Go to the next import */
643 MiSnapThunk(IN PVOID DllBase
,
645 IN PIMAGE_THUNK_DATA Name
,
646 IN PIMAGE_THUNK_DATA Address
,
647 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
649 IN BOOLEAN SnapForwarder
,
650 OUT PCHAR
*MissingApi
)
655 PUSHORT OrdinalTable
;
656 PIMAGE_IMPORT_BY_NAME NameImport
;
658 ULONG Low
= 0, Mid
= 0, High
;
661 PCHAR MissingForwarder
;
662 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
665 UNICODE_STRING ForwarderName
;
666 PLIST_ENTRY NextEntry
;
667 PLDR_DATA_TABLE_ENTRY LdrEntry
;
668 ULONG ForwardExportSize
;
669 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
670 PIMAGE_IMPORT_BY_NAME ForwardName
;
672 IMAGE_THUNK_DATA ForwardThunk
;
675 /* Check if this is an ordinal */
676 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
677 if ((IsOrdinal
) && !(SnapForwarder
))
679 /* Get the ordinal number and set it as missing */
680 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
681 ExportDirectory
->Base
);
682 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
686 /* Get the VA if we don't have to snap */
687 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
688 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
690 /* Copy the procedure name */
692 (PCHAR
)&NameImport
->Name
[0],
693 MAXIMUM_FILENAME_LENGTH
- 1);
695 /* Setup name tables */
696 DPRINT("Import name: %s\n", NameImport
->Name
);
697 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
698 ExportDirectory
->AddressOfNames
);
699 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
700 ExportDirectory
->AddressOfNameOrdinals
);
702 /* Get the hint and check if it's valid */
703 Hint
= NameImport
->Hint
;
704 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
705 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
707 /* We have a match, get the ordinal number from here */
708 Ordinal
= OrdinalTable
[Hint
];
712 /* Do a binary search */
713 High
= ExportDirectory
->NumberOfNames
- 1;
716 /* Get new middle value */
717 Mid
= (Low
+ High
) >> 1;
720 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
738 /* Check if we couldn't find it */
739 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
741 /* Otherwise, this is the ordinal */
742 Ordinal
= OrdinalTable
[Mid
];
746 /* Check if the ordinal is invalid */
747 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
750 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
754 /* In case the forwarder is missing */
755 MissingForwarder
= NameBuffer
;
757 /* Resolve the address and write it */
758 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
759 ExportDirectory
->AddressOfFunctions
);
760 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
762 /* Assume success from now on */
763 Status
= STATUS_SUCCESS
;
765 /* Check if the function is actually a forwarder */
766 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
767 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
769 /* Now assume failure in case the forwarder doesn't exist */
770 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
772 /* Build the forwarder name */
773 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
774 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
777 DllName
.MaximumLength
= DllName
.Length
;
780 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
784 /* We failed, just return an error */
788 /* Loop the module list */
789 NextEntry
= PsLoadedModuleList
.Flink
;
790 while (NextEntry
!= &PsLoadedModuleList
)
792 /* Get the loader entry */
793 LdrEntry
= CONTAINING_RECORD(NextEntry
,
794 LDR_DATA_TABLE_ENTRY
,
797 /* Check if it matches */
798 if (RtlPrefixString((PSTRING
)&ForwarderName
,
799 (PSTRING
)&LdrEntry
->BaseDllName
,
802 /* Get the forwarder export directory */
803 ForwardExportDirectory
=
804 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
806 IMAGE_DIRECTORY_ENTRY_EXPORT
,
808 if (!ForwardExportDirectory
) break;
810 /* Allocate a name entry */
811 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
813 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
814 sizeof(*ForwardName
) +
817 if (!ForwardName
) break;
820 RtlCopyMemory(&ForwardName
->Name
[0],
821 DllName
.Buffer
+ DllName
.Length
,
823 ForwardName
->Hint
= 0;
825 /* Set the new address */
826 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
828 /* Snap the forwarder */
829 Status
= MiSnapThunk(LdrEntry
->DllBase
,
833 ForwardExportDirectory
,
838 /* Free the forwarder name and set the thunk */
839 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
840 Address
->u1
= ForwardThunk
.u1
;
844 /* Go to the next entry */
845 NextEntry
= NextEntry
->Flink
;
849 RtlFreeUnicodeString(&ForwarderName
);
859 MmUnloadSystemImage(IN PVOID ImageHandle
)
861 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
862 PVOID BaseAddress
= LdrEntry
->DllBase
;
865 BOOLEAN HadEntry
= FALSE
;
867 /* Acquire the loader lock */
868 KeEnterCriticalRegion();
869 KeWaitForSingleObject(&MmSystemLoadLock
,
875 /* Check if this driver was loaded at boot and didn't get imports parsed */
876 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
878 /* We should still be alive */
879 ASSERT(LdrEntry
->LoadCount
!= 0);
880 LdrEntry
->LoadCount
--;
882 /* Check if we're still loaded */
883 if (LdrEntry
->LoadCount
) goto Done
;
885 /* We should cleanup... are symbols loaded */
886 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
888 /* Create the ANSI name */
889 Status
= RtlUnicodeStringToAnsiString(&TempName
,
890 &LdrEntry
->BaseDllName
,
892 if (NT_SUCCESS(Status
))
894 /* Unload the symbols */
895 DbgUnLoadImageSymbols(&TempName
,
897 (ULONG_PTR
)ZwCurrentProcess());
898 RtlFreeAnsiString(&TempName
);
902 /* FIXME: Free the driver */
903 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
904 //MmFreeSection(LdrEntry->DllBase);
906 /* Check if we're linked in */
907 if (LdrEntry
->InLoadOrderLinks
.Flink
)
910 MiProcessLoaderEntry(LdrEntry
, FALSE
);
914 /* Dereference and clear the imports */
915 MiDereferenceImports(LdrEntry
->LoadedImports
);
916 MiClearImports(LdrEntry
);
918 /* Check if the entry needs to go away */
921 /* Check if it had a name */
922 if (LdrEntry
->FullDllName
.Buffer
)
925 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
928 /* Check if we had a section */
929 if (LdrEntry
->SectionPointer
)
932 ObDereferenceObject(LdrEntry
->SectionPointer
);
936 ExFreePool(LdrEntry
);
939 /* Release the system lock and return */
941 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
942 KeLeaveCriticalRegion();
943 return STATUS_SUCCESS
;
948 MiResolveImageReferences(IN PVOID ImageBase
,
949 IN PUNICODE_STRING ImageFileDirectory
,
950 IN PUNICODE_STRING NamePrefix OPTIONAL
,
951 OUT PCHAR
*MissingApi
,
952 OUT PWCHAR
*MissingDriver
,
953 OUT PLOAD_IMPORTS
*LoadImports
)
955 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
956 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
957 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
958 PLOAD_IMPORTS LoadedImports
, NewImports
;
959 ULONG GdiLink
, NormalLink
, i
;
960 BOOLEAN ReferenceNeeded
, Loaded
;
961 ANSI_STRING TempString
;
962 UNICODE_STRING NameString
, DllName
;
963 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
964 PVOID ImportBase
, DllBase
;
965 PLIST_ENTRY NextEntry
;
966 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
968 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
970 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
971 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
973 /* Assume no imports */
974 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
976 /* Get the import descriptor */
977 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
979 IMAGE_DIRECTORY_ENTRY_IMPORT
,
981 if (!ImportDescriptor
) return STATUS_SUCCESS
;
983 /* Loop all imports to count them */
984 for (CurrentImport
= ImportDescriptor
;
985 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
992 /* Make sure we have non-zero imports */
995 /* Calculate and allocate the list we'll need */
996 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
997 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1003 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1004 LoadedImports
->Count
= ImportCount
;
1010 LoadedImports
= NULL
;
1013 /* Reset the import count and loop descriptors again */
1014 ImportCount
= GdiLink
= NormalLink
= 0;
1015 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1018 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1020 /* Check if this is a GDI driver */
1022 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1024 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1025 NormalLink
= NormalLink
|
1026 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1027 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1028 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1029 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1031 /* Check if this is a valid GDI driver */
1032 if ((GdiLink
) && (NormalLink
))
1034 /* It's not, it's importing stuff it shouldn't be! */
1035 MiDereferenceImports(LoadedImports
);
1036 if (LoadedImports
) ExFreePool(LoadedImports
);
1037 return STATUS_PROCEDURE_NOT_FOUND
;
1040 /* Check for user-mode printer or video card drivers, which don't belong */
1041 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1042 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1043 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1044 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1045 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1046 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1048 /* This is not kernel code */
1049 MiDereferenceImports(LoadedImports
);
1050 if (LoadedImports
) ExFreePool(LoadedImports
);
1051 return STATUS_PROCEDURE_NOT_FOUND
;
1054 /* Check if this is a "core" import, which doesn't get referenced */
1055 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1056 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1057 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1059 /* Don't reference this */
1060 ReferenceNeeded
= FALSE
;
1064 /* Reference these modules */
1065 ReferenceNeeded
= TRUE
;
1068 /* Now setup a unicode string for the import */
1069 RtlInitAnsiString(&TempString
, ImportName
);
1070 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1071 if (!NT_SUCCESS(Status
))
1074 MiDereferenceImports(LoadedImports
);
1075 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1079 /* We don't support name prefixes yet */
1080 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1082 /* Remember that we haven't loaded the import at this point */
1087 /* Loop the driver list */
1088 NextEntry
= PsLoadedModuleList
.Flink
;
1089 while (NextEntry
!= &PsLoadedModuleList
)
1091 /* Get the loader entry and compare the name */
1092 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1093 LDR_DATA_TABLE_ENTRY
,
1095 if (RtlEqualUnicodeString(&NameString
,
1096 &LdrEntry
->BaseDllName
,
1099 /* Get the base address */
1100 ImportBase
= LdrEntry
->DllBase
;
1102 /* Check if we haven't loaded yet, and we need references */
1103 if (!(Loaded
) && (ReferenceNeeded
))
1105 /* Make sure we're not already loading */
1106 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1108 /* Increase the load count */
1109 LdrEntry
->LoadCount
++;
1113 /* Done, break out */
1117 /* Go to the next entry */
1118 NextEntry
= NextEntry
->Flink
;
1121 /* Check if we haven't loaded the import yet */
1124 /* Setup the import DLL name */
1125 DllName
.MaximumLength
= NameString
.Length
+
1126 ImageFileDirectory
->Length
+
1127 sizeof(UNICODE_NULL
);
1128 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1129 DllName
.MaximumLength
,
1133 /* Setup the base length and copy it */
1134 DllName
.Length
= ImageFileDirectory
->Length
;
1135 RtlCopyMemory(DllName
.Buffer
,
1136 ImageFileDirectory
->Buffer
,
1137 ImageFileDirectory
->Length
);
1139 /* Now add the import name and null-terminate it */
1140 RtlAppendStringToString((PSTRING
)&DllName
,
1141 (PSTRING
)&NameString
);
1142 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / sizeof(WCHAR
)] = UNICODE_NULL
;
1144 /* Load the image */
1145 Status
= MmLoadSystemImage(&DllName
,
1151 if (NT_SUCCESS(Status
))
1153 /* We can free the DLL Name */
1154 ExFreePool(DllName
.Buffer
);
1158 /* Fill out the information for the error */
1159 *MissingDriver
= DllName
.Buffer
;
1160 *(PULONG
)MissingDriver
|= 1;
1166 /* We're out of resources */
1167 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1170 /* Check if we're OK until now */
1171 if (NT_SUCCESS(Status
))
1173 /* We're now loaded */
1177 ASSERT(DllBase
= DllEntry
->DllBase
);
1179 /* Call the initialization routines */
1180 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1181 if (!NT_SUCCESS(Status
))
1183 /* We failed, unload the image */
1184 MmUnloadSystemImage(DllEntry
);
1190 /* Check if we failed by here */
1191 if (!NT_SUCCESS(Status
))
1193 /* Cleanup and return */
1194 RtlFreeUnicodeString(&NameString
);
1195 MiDereferenceImports(LoadedImports
);
1196 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1200 /* Loop again to make sure that everything is OK */
1204 /* Check if we're support to reference this import */
1205 if ((ReferenceNeeded
) && (LoadedImports
))
1207 /* Make sure we're not already loading */
1208 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1211 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1216 /* Free the import name */
1217 RtlFreeUnicodeString(&NameString
);
1219 /* Set the missing driver name and get the export directory */
1220 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1221 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1223 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1225 if (!ExportDirectory
)
1227 /* Cleanup and return */
1228 MiDereferenceImports(LoadedImports
);
1229 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1230 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1233 /* Make sure we have an IAT */
1234 if (ImportDescriptor
->OriginalFirstThunk
)
1236 /* Get the first thunks */
1237 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1238 ImportDescriptor
->OriginalFirstThunk
);
1239 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1240 ImportDescriptor
->FirstThunk
);
1243 while (OrigThunk
->u1
.AddressOfData
)
1246 Status
= MiSnapThunk(ImportBase
,
1254 if (!NT_SUCCESS(Status
))
1256 /* Cleanup and return */
1257 MiDereferenceImports(LoadedImports
);
1258 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1262 /* Reset the buffer */
1263 *MissingApi
= MissingApiBuffer
;
1267 /* Go to the next import */
1271 /* Check if we have an import list */
1274 /* Reset the count again, and loop entries*/
1276 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1278 if (LoadedImports
->Entry
[i
])
1280 /* Got an entry, OR it with 1 in case it's the single entry */
1281 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1282 MM_SYSLDR_SINGLE_ENTRY
);
1287 /* Check if we had no imports */
1290 /* Free the list and set it to no imports */
1291 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1292 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1294 else if (ImportCount
== 1)
1296 /* Just one entry, we can free the table and only use our entry */
1297 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1298 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1300 else if (ImportCount
!= LoadedImports
->Count
)
1302 /* Allocate a new list */
1303 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1304 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1310 NewImports
->Count
= 0;
1312 /* Loop all the imports */
1313 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1315 /* Make sure it's valid */
1316 if (LoadedImports
->Entry
[i
])
1319 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1320 NewImports
->Count
++;
1324 /* Free the old copy */
1325 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1326 LoadedImports
= NewImports
;
1330 /* Return the list */
1331 *LoadImports
= LoadedImports
;
1334 /* Return success */
1335 return STATUS_SUCCESS
;
1340 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1342 PLIST_ENTRY NextEntry
;
1344 PIMAGE_NT_HEADERS NtHeader
;
1345 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1346 PIMAGE_FILE_HEADER FileHeader
;
1347 BOOLEAN ValidRelocs
;
1348 PIMAGE_DATA_DIRECTORY DataDirectory
;
1349 PVOID DllBase
, NewImageAddress
;
1351 PMMPTE PointerPte
, StartPte
, LastPte
;
1352 PFN_NUMBER PteCount
;
1354 MMPTE TempPte
, OldPte
;
1356 /* Loop driver list */
1357 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1358 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1359 NextEntry
= NextEntry
->Flink
)
1361 /* Get the loader entry and NT header */
1362 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1363 LDR_DATA_TABLE_ENTRY
,
1365 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1368 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1370 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1371 &LdrEntry
->FullDllName
);
1373 /* Skip kernel and HAL */
1374 /* ROS HACK: Skip BOOTVID/KDCOM too */
1376 if (i
<= 4) continue;
1378 /* Skip non-drivers */
1379 if (!NtHeader
) continue;
1381 /* Get the file header and make sure we can relocate */
1382 FileHeader
= &NtHeader
->FileHeader
;
1383 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1384 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1385 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1387 /* Everything made sense until now, check the relocation section too */
1388 DataDirectory
= &NtHeader
->OptionalHeader
.
1389 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1390 if (!DataDirectory
->VirtualAddress
)
1392 /* We don't really have relocations */
1393 ValidRelocs
= FALSE
;
1397 /* Make sure the size is valid */
1398 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1399 LdrEntry
->SizeOfImage
)
1401 /* They're not, skip */
1405 /* We have relocations */
1409 /* Remember the original address */
1410 DllBase
= LdrEntry
->DllBase
;
1412 /* Get the first PTE and the number of PTEs we'll need */
1413 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1414 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1415 LastPte
= StartPte
+ PteCount
;
1418 while (PointerPte
< LastPte
)
1420 /* Mark the page modified in the PFN database */
1421 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1422 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1423 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1424 Pfn1
->u3
.e1
.Modified
= TRUE
;
1430 /* Now reserve system PTEs for the image */
1431 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1434 /* Shouldn't happen */
1435 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1439 /* This is the new virtual address for the module */
1440 LastPte
= PointerPte
+ PteCount
;
1441 NewImageAddress
= MiPteToAddress(PointerPte
);
1444 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1445 ASSERT(ExpInitializationPhase
== 0);
1447 /* Loop the new driver PTEs */
1448 TempPte
= ValidKernelPte
;
1449 while (PointerPte
< LastPte
)
1451 /* Copy the old data */
1453 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1455 /* Set page number from the loader's memory */
1456 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1459 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1460 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
1461 *PointerPte
= TempPte
;
1468 /* Update position */
1469 PointerPte
-= PteCount
;
1472 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1474 /* Set the image base to the address where the loader put it */
1475 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1477 /* Check if we had relocations */
1480 /* Relocate the image */
1481 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1485 STATUS_CONFLICTING_ADDRESSES
,
1486 STATUS_INVALID_IMAGE_FORMAT
);
1487 if (!NT_SUCCESS(Status
))
1489 /* This shouldn't happen */
1490 DPRINT1("Relocations failed!\n");
1495 /* Update the loader entry */
1496 LdrEntry
->DllBase
= NewImageAddress
;
1498 /* Update the thunks */
1499 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1500 MiUpdateThunks(LoaderBlock
,
1503 LdrEntry
->SizeOfImage
);
1505 /* Update the loader entry */
1506 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1507 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1508 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1509 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1511 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1517 MiBuildImportsForBootDrivers(VOID
)
1519 PLIST_ENTRY NextEntry
, NextEntry2
;
1520 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1521 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1522 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1523 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1524 PLOAD_IMPORTS LoadedImports
;
1525 ULONG LoadedImportsSize
, ImportSize
;
1526 PULONG_PTR ImageThunk
;
1527 ULONG_PTR DllBase
, DllEnd
;
1528 ULONG Modules
= 0, i
, j
= 0;
1529 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1531 /* Initialize variables */
1532 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1534 /* Loop the loaded module list... we are early enough that no lock is needed */
1535 NextEntry
= PsLoadedModuleList
.Flink
;
1536 while (NextEntry
!= &PsLoadedModuleList
)
1539 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1540 LDR_DATA_TABLE_ENTRY
,
1543 /* Check if it's the kernel or HAL */
1544 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1547 KernelEntry
= LdrEntry
;
1549 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1552 HalEntry
= LdrEntry
;
1555 /* Check if this is a driver DLL */
1556 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1558 /* Check if this is the HAL or kernel */
1559 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1561 /* Add a reference */
1562 LdrEntry
->LoadCount
= 1;
1566 /* No referencing needed */
1567 LdrEntry
->LoadCount
= 0;
1572 /* No referencing needed */
1573 LdrEntry
->LoadCount
= 0;
1576 /* Remember this came from the loader */
1577 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1580 NextEntry
= NextEntry
->Flink
;
1584 /* We must have at least found the kernel and HAL */
1585 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1587 /* Allocate the list */
1588 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), 'TDmM');
1589 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1591 /* Loop the loaded module list again */
1592 NextEntry
= PsLoadedModuleList
.Flink
;
1593 while (NextEntry
!= &PsLoadedModuleList
)
1596 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1597 LDR_DATA_TABLE_ENTRY
,
1599 #ifdef _WORKING_LOADER_
1600 /* Get its imports */
1601 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1603 IMAGE_DIRECTORY_ENTRY_IAT
,
1607 /* Get its imports */
1608 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1610 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1612 if (!ImportDescriptor
)
1616 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1617 NextEntry
= NextEntry
->Flink
;
1621 /* Clear the list and count the number of IAT thunks */
1622 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1623 #ifdef _WORKING_LOADER_
1624 ImportSize
/= sizeof(ULONG_PTR
);
1626 /* Scan the thunks */
1627 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1629 i
= DllBase
= DllEnd
= 0;
1630 while ((ImportDescriptor
->Name
) &&
1631 (ImportDescriptor
->OriginalFirstThunk
))
1633 /* Get the image thunk */
1634 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1635 ImportDescriptor
->FirstThunk
);
1639 /* Do we already have an address? */
1642 /* Is the thunk in the same address? */
1643 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1645 /* Skip it, we already have a reference for it */
1646 ASSERT(EntryArray
[j
]);
1652 /* Loop the loaded module list to locate this address owner */
1654 NextEntry2
= PsLoadedModuleList
.Flink
;
1655 while (NextEntry2
!= &PsLoadedModuleList
)
1658 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1659 LDR_DATA_TABLE_ENTRY
,
1662 /* Get the address range for this module */
1663 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1664 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1666 /* Check if this IAT entry matches it */
1667 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1670 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1671 EntryArray
[j
] = LdrEntry2
;
1675 /* Keep searching */
1676 NextEntry2
= NextEntry2
->Flink
;
1680 /* Do we have a thunk outside the range? */
1681 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1686 /* Should not be happening */
1687 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1688 LdrEntry
, ImageThunk
, *ImageThunk
);
1692 /* Reset if we hit this */
1695 #ifndef _WORKING_LOADER_
1704 /* Now scan how many imports we really have */
1705 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1707 /* Skip HAL and kernel */
1708 if ((EntryArray
[i
]) &&
1709 (EntryArray
[i
] != HalEntry
) &&
1710 (EntryArray
[i
] != KernelEntry
))
1712 /* A valid reference */
1713 LastEntry
= EntryArray
[i
];
1718 /* Do we have any imports after all? */
1722 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1724 else if (ImportSize
== 1)
1726 /* A single entry import */
1727 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
1728 LastEntry
->LoadCount
++;
1732 /* We need an import table */
1733 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
1734 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1737 ASSERT(LoadedImports
);
1739 /* Save the count */
1740 LoadedImports
->Count
= ImportSize
;
1742 /* Now copy all imports */
1743 for (i
= 0, j
= 0; i
< Modules
; i
++)
1745 /* Skip HAL and kernel */
1746 if ((EntryArray
[i
]) &&
1747 (EntryArray
[i
] != HalEntry
) &&
1748 (EntryArray
[i
] != KernelEntry
))
1750 /* A valid reference */
1751 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
1752 LoadedImports
->Entry
[j
] = EntryArray
[i
];
1753 EntryArray
[i
]->LoadCount
++;
1758 /* Should had as many entries as we expected */
1759 ASSERT(j
== ImportSize
);
1760 LdrEntry
->LoadedImports
= LoadedImports
;
1764 NextEntry
= NextEntry
->Flink
;
1767 /* Free the initial array */
1768 ExFreePool(EntryArray
);
1770 /* FIXME: Might not need to keep the HAL/Kernel imports around */
1772 /* Kernel and HAL are loaded at boot */
1773 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1774 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1776 /* All worked well */
1777 return STATUS_SUCCESS
;
1782 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1785 PIMAGE_NT_HEADERS NtHeaders
;
1786 PIMAGE_SECTION_HEADER SectionHeader
;
1787 ULONG Sections
, Size
;
1789 /* Get the kernel section header */
1790 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1791 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
1792 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
1794 /* Loop all the sections */
1795 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1798 /* Grab the size of the section */
1799 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
1801 /* Check for .RSRC section */
1802 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
1804 /* Remember the PTEs so we can modify them later */
1805 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
1806 SectionHeader
->VirtualAddress
);
1807 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
1808 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
1810 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
1812 /* POOLCODE vs. POOLMI */
1813 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
1815 /* Found Ex* Pool code */
1816 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1817 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1819 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
1821 /* Found Mm* Pool code */
1822 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1823 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1826 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
1827 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
1829 /* Found MISYSPTE (Mm System PTE code)*/
1830 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1831 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
1842 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1844 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1845 PLIST_ENTRY ListHead
, NextEntry
;
1848 /* Setup the loaded module list and locks */
1849 ExInitializeResourceLite(&PsLoadedModuleResource
);
1850 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1851 InitializeListHead(&PsLoadedModuleList
);
1853 /* Get loop variables and the kernel entry */
1854 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1855 NextEntry
= ListHead
->Flink
;
1856 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1857 LDR_DATA_TABLE_ENTRY
,
1859 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1861 /* Locate resource section, pool code, and system pte code */
1862 MiLocateKernelSections(LdrEntry
);
1864 /* Loop the loader block */
1865 while (NextEntry
!= ListHead
)
1867 /* Get the loader entry */
1868 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1869 LDR_DATA_TABLE_ENTRY
,
1872 /* FIXME: ROS HACK. Make sure this is a driver */
1873 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1875 /* Skip this entry */
1876 NextEntry
= NextEntry
->Flink
;
1880 /* Calculate the size we'll need and allocate a copy */
1881 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1882 LdrEntry
->BaseDllName
.MaximumLength
+
1883 sizeof(UNICODE_NULL
);
1884 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1885 if (!NewEntry
) return FALSE
;
1887 /* Copy the entry over */
1888 *NewEntry
= *LdrEntry
;
1890 /* Allocate the name */
1891 NewEntry
->FullDllName
.Buffer
=
1892 ExAllocatePoolWithTag(PagedPool
,
1893 LdrEntry
->FullDllName
.MaximumLength
+
1894 sizeof(UNICODE_NULL
),
1896 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1898 /* Set the base name */
1899 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1901 /* Copy the full and base name */
1902 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1903 LdrEntry
->FullDllName
.Buffer
,
1904 LdrEntry
->FullDllName
.MaximumLength
);
1905 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1906 LdrEntry
->BaseDllName
.Buffer
,
1907 LdrEntry
->BaseDllName
.MaximumLength
);
1909 /* Null-terminate the base name */
1910 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1911 sizeof(WCHAR
)] = UNICODE_NULL
;
1913 /* Insert the entry into the list */
1914 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1915 NextEntry
= NextEntry
->Flink
;
1918 /* Build the import lists for the boot drivers */
1919 MiBuildImportsForBootDrivers();
1927 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
1928 IN OUT PVOID
*ImageBaseAddress
,
1929 IN PUNICODE_STRING BaseImageName
,
1930 IN BOOLEAN BootDriver
)
1932 PLIST_ENTRY NextEntry
;
1933 BOOLEAN DriverFound
= FALSE
;
1934 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
1935 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
1936 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
1939 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
1940 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
1943 /* Make sure there's enough system PTEs for a large page driver */
1944 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
1949 /* This happens if the registry key had a "*" (wildcard) in it */
1950 if (MiLargePageAllDrivers
== 0)
1952 /* It didn't, so scan the list */
1953 NextEntry
= MiLargePageDriverList
.Flink
;
1954 while (NextEntry
!= &MiLargePageDriverList
)
1956 /* Check if the driver name matches */
1957 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
1958 MI_LARGE_PAGE_DRIVER_ENTRY
,
1960 if (RtlEqualUnicodeString(BaseImageName
,
1961 &LargePageDriverEntry
->BaseName
,
1964 /* Enable large pages for this driver */
1970 NextEntry
= NextEntry
->Flink
;
1973 /* If we didn't find the driver, it doesn't need large pages */
1974 if (DriverFound
== FALSE
) return FALSE
;
1977 /* Nothing to do yet */
1978 DPRINT1("Large pages not supported!\n");
1984 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
1985 IN ULONG SectionProtection
)
1987 ULONG Protection
= MM_ZERO_ACCESS
;
1989 /* Check if the caller gave anything */
1990 if (SectionProtection
)
1992 /* Always turn on execute access */
1993 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
1995 /* Check if the registry setting is on or not */
1996 if (!MmEnforceWriteProtection
)
1998 /* Turn on write access too */
1999 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2003 /* Convert to internal PTE flags */
2004 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2005 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2007 /* Check for write access */
2008 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2010 /* Session space is not supported */
2013 DPRINT1("Session drivers not supported\n");
2014 ASSERT(SessionSpace
== FALSE
);
2018 /* Convert to internal PTE flag */
2019 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2023 /* If there's no access at all by now, convert to internal no access flag */
2024 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2026 /* Return the computed PTE protection */
2032 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2034 IN ULONG ProtectionMask
)
2036 /* I'm afraid to introduce regressions at the moment... */
2042 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2044 PIMAGE_NT_HEADERS NtHeaders
;
2045 PIMAGE_SECTION_HEADER Section
;
2046 PFN_NUMBER DriverPages
;
2047 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
, ProtectionMask
;
2048 ULONG Sections
, Size
;
2049 ULONG_PTR BaseAddress
, CurrentAddress
;
2050 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2051 ULONG CurrentMask
, CombinedMask
= 0;
2054 /* No need to write protect physical memory-backed drivers (large pages) */
2055 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2057 /* Get the image headers */
2058 NtHeaders
= RtlImageNtHeader(ImageBase
);
2059 if (!NtHeaders
) return;
2061 /* Check if this is a session driver or not */
2062 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2064 /* Don't touch NT4 drivers */
2065 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2066 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2071 DPRINT1("Session drivers not supported\n");
2075 /* These are the only protection masks we care about */
2076 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2078 /* Calculate the number of pages this driver is occupying */
2079 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2081 /* Get the number of sections and the first section header */
2082 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2083 ASSERT(Sections
!= 0);
2084 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2086 /* Loop all the sections */
2087 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2090 /* Get the section size */
2091 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2093 /* Get its virtual address */
2094 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2095 if (BaseAddress
< CurrentAddress
)
2097 /* Windows doesn't like these */
2098 DPRINT1("Badly linked image!\n");
2102 /* Remember the current address */
2103 CurrentAddress
= BaseAddress
+ Size
- 1;
2110 /* Get the number of sections and the first section header */
2111 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2112 ASSERT(Sections
!= 0);
2113 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2115 /* Set the address at the end to initialize the loop */
2116 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2117 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2119 /* Set the PTE points for the image, and loop its sections */
2120 StartPte
= MiAddressToPte(ImageBase
);
2121 LastPte
= StartPte
+ DriverPages
;
2124 /* Get the section size */
2125 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2127 /* Get its virtual address and PTE */
2128 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2129 PointerPte
= MiAddressToPte(BaseAddress
);
2131 /* Check if we were already protecting a run, and found a new run */
2132 if ((ComboPte
) && (PointerPte
> ComboPte
))
2134 /* Compute protection */
2135 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2138 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2140 /* Check for overlap */
2141 if (ComboPte
== StartPte
) StartPte
++;
2143 /* One done, reset variables */
2145 CombinedProtection
= 0;
2148 /* Break out when needed */
2149 if (PointerPte
>= LastPte
) break;
2151 /* Get the requested protection from the image header */
2152 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2153 if (SectionProtection
== CurrentProtection
)
2155 /* Same protection, so merge the request */
2156 CurrentAddress
= BaseAddress
+ Size
- 1;
2164 /* This is now a new section, so close up the old one */
2165 CurrentPte
= MiAddressToPte(CurrentAddress
);
2167 /* Check for overlap */
2168 if (CurrentPte
== PointerPte
)
2170 /* Skip the last PTE, since it overlaps with us */
2173 /* And set the PTE we will merge with */
2174 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2175 ComboPte
= PointerPte
;
2177 /* Get the most flexible protection by merging both */
2178 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2181 /* Loop any PTEs left */
2182 if (CurrentPte
>= StartPte
)
2185 ASSERT(StartPte
< LastPte
);
2187 /* Make sure we don't overflow past the last PTE in the driver */
2188 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2189 ASSERT(CurrentPte
>= StartPte
);
2191 /* Compute the protection and set it */
2192 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2193 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2197 StartPte
= PointerPte
;
2198 CurrentAddress
= BaseAddress
+ Size
- 1;
2199 CurrentProtection
= SectionProtection
;
2206 /* Is there a leftover section to merge? */
2209 /* Compute and set the protection */
2210 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2211 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2213 /* Handle overlap */
2214 if (ComboPte
== StartPte
) StartPte
++;
2217 /* Finally, handle the last section */
2218 CurrentPte
= MiPteToAddress(CurrentAddress
);
2219 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2221 /* Handle overlap */
2222 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2223 ASSERT(CurrentPte
>= StartPte
);
2225 /* Compute and set the protection */
2226 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2227 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2233 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2237 PETHREAD CurrentThread
;
2238 PFN_NUMBER PageCount
= 0, PageFrameIndex
;
2242 /* Get the driver's base address */
2243 ImageBase
= MiPteToAddress(PointerPte
);
2244 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2246 /* If this is a large page, it's stuck in physical memory */
2247 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2249 /* We should lock the system working set -- we don't have one yet, so just be consistent */
2250 CurrentThread
= PsGetCurrentThread();
2251 KeEnterGuardedRegion();
2252 ASSERT((CurrentThread
->OwnsSystemWorkingSetExclusive
== 0) &&
2253 (CurrentThread
->OwnsSystemWorkingSetShared
== 0));
2254 CurrentThread
->OwnsSystemWorkingSetExclusive
= 1;
2257 while (PointerPte
<= LastPte
)
2259 /* Check for valid PTE */
2260 if (PointerPte
->u
.Hard
.Valid
== 1)
2262 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2263 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2264 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2266 /* No working sets in ReactOS yet */
2270 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2274 /* Release the working set "lock" */
2275 ASSERT(KeAreAllApcsDisabled() == TRUE
);
2276 CurrentThread
->OwnsSystemWorkingSetExclusive
= 0;
2277 KeLeaveGuardedRegion();
2279 /* Do we have any driver pages? */
2282 /* Update counters */
2283 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2289 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2291 ULONG_PTR ImageBase
;
2292 PIMAGE_NT_HEADERS NtHeaders
;
2293 ULONG Sections
, Alignment
, Size
;
2294 PIMAGE_SECTION_HEADER Section
;
2295 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2296 if (MmDisablePagingExecutive
) return;
2298 /* Get the driver base address and its NT header */
2299 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2300 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2301 if (!NtHeaders
) return;
2303 /* Get the sections and their alignment */
2304 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2305 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2307 /* Loop each section */
2308 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2311 /* Find PAGE or .edata */
2312 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2313 (*(PULONG
)Section
->Name
== 'ade.'))
2315 /* Had we already done some work? */
2318 /* Nope, setup the first PTE address */
2319 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2324 /* Compute the size */
2325 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2327 /* Find the last PTE that maps this section */
2328 LastPte
= MiAddressToPte(ImageBase
+
2329 Section
->VirtualAddress
+
2336 /* Had we found a section before? */
2339 /* Mark it as pageable */
2340 MiSetPagingOfDriver(PointerPte
, LastPte
);
2345 /* Keep searching */
2350 /* Handle the straggler */
2351 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2356 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2358 PIMAGE_NT_HEADERS NtHeader
;
2361 /* Get NT Headers */
2362 NtHeader
= RtlImageNtHeader(BaseAddress
);
2365 /* Check if this image is only safe for UP while we have 2+ CPUs */
2366 if ((KeNumberProcessors
> 1) &&
2367 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2374 /* Otherwise, it's safe */
2380 MmCheckSystemImage(IN HANDLE ImageHandle
,
2381 IN BOOLEAN PurgeSection
)
2384 HANDLE SectionHandle
;
2385 PVOID ViewBase
= NULL
;
2386 SIZE_T ViewSize
= 0;
2387 IO_STATUS_BLOCK IoStatusBlock
;
2388 FILE_STANDARD_INFORMATION FileStandardInfo
;
2389 KAPC_STATE ApcState
;
2390 PIMAGE_NT_HEADERS NtHeaders
;
2391 OBJECT_ATTRIBUTES ObjectAttributes
;
2394 /* Setup the object attributes */
2395 InitializeObjectAttributes(&ObjectAttributes
,
2397 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2401 /* Create a section for the DLL */
2402 Status
= ZwCreateSection(&SectionHandle
,
2403 SECTION_MAP_EXECUTE
,
2409 if (!NT_SUCCESS(Status
)) return Status
;
2411 /* Make sure we're in the system process */
2412 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2415 Status
= ZwMapViewOfSection(SectionHandle
,
2425 if (!NT_SUCCESS(Status
))
2427 /* We failed, close the handle and return */
2428 KeUnstackDetachProcess(&ApcState
);
2429 ZwClose(SectionHandle
);
2433 /* Now query image information */
2434 Status
= ZwQueryInformationFile(ImageHandle
,
2437 sizeof(FileStandardInfo
),
2438 FileStandardInformation
);
2439 if (NT_SUCCESS(Status
))
2441 /* First, verify the checksum */
2442 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2447 /* Set checksum failure */
2448 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2452 /* Make sure it's a real image */
2453 NtHeaders
= RtlImageNtHeader(ViewBase
);
2456 /* Set checksum failure */
2457 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2461 /* Make sure it's for the correct architecture */
2462 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2463 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2465 /* Set protection failure */
2466 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2470 /* Check that it's a valid SMP image if we have more then one CPU */
2471 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2473 /* Otherwise it's not the right image */
2474 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2478 /* Unmap the section, close the handle, and return status */
2480 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2481 KeUnstackDetachProcess(&ApcState
);
2482 ZwClose(SectionHandle
);
2488 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2489 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2490 IN PUNICODE_STRING LoadedName OPTIONAL
,
2492 OUT PVOID
*ModuleObject
,
2493 OUT PVOID
*ImageBaseAddress
)
2495 PVOID ModuleLoadBase
= NULL
;
2497 HANDLE FileHandle
= NULL
;
2498 OBJECT_ATTRIBUTES ObjectAttributes
;
2499 IO_STATUS_BLOCK IoStatusBlock
;
2500 PIMAGE_NT_HEADERS NtHeader
;
2501 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2502 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2503 ULONG EntrySize
, DriverSize
;
2504 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2505 PCHAR MissingApiName
, Buffer
;
2506 PWCHAR MissingDriverName
;
2507 HANDLE SectionHandle
;
2508 ACCESS_MASK DesiredAccess
;
2509 PVOID Section
= NULL
;
2510 BOOLEAN LockOwned
= FALSE
;
2511 PLIST_ENTRY NextEntry
;
2512 IMAGE_INFO ImageInfo
;
2516 /* Detect session-load */
2520 ASSERT(NamePrefix
== NULL
);
2521 ASSERT(LoadedName
== NULL
);
2523 /* Make sure the process is in session too */
2524 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2527 /* Allocate a buffer we'll use for names */
2528 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, 'nLmM');
2529 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2531 /* Check for a separator */
2532 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2537 /* Loop the path until we get to the base name */
2538 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2539 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2541 /* Get the length */
2542 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2543 BaseLength
*= sizeof(WCHAR
);
2545 /* Setup the string */
2546 BaseName
.Length
= (USHORT
)BaseLength
;
2547 BaseName
.Buffer
= p
;
2551 /* Otherwise, we already have a base name */
2552 BaseName
.Length
= FileName
->Length
;
2553 BaseName
.Buffer
= FileName
->Buffer
;
2556 /* Setup the maximum length */
2557 BaseName
.MaximumLength
= BaseName
.Length
;
2559 /* Now compute the base directory */
2560 BaseDirectory
= *FileName
;
2561 BaseDirectory
.Length
-= BaseName
.Length
;
2562 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2564 /* And the prefix, which for now is just the name itself */
2565 PrefixName
= *FileName
;
2567 /* Check if we have a prefix */
2568 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2570 /* Check if we already have a name, use it instead */
2571 if (LoadedName
) BaseName
= *LoadedName
;
2573 /* Check for loader snap debugging */
2574 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2576 /* Print out standard string */
2577 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2578 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2581 /* Acquire the load lock */
2583 ASSERT(LockOwned
== FALSE
);
2585 KeEnterCriticalRegion();
2586 KeWaitForSingleObject(&MmSystemLoadLock
,
2592 /* Scan the module list */
2593 NextEntry
= PsLoadedModuleList
.Flink
;
2594 while (NextEntry
!= &PsLoadedModuleList
)
2596 /* Get the entry and compare the names */
2597 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2598 LDR_DATA_TABLE_ENTRY
,
2600 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2602 /* Found it, break out */
2607 NextEntry
= NextEntry
->Flink
;
2610 /* Check if we found the image */
2611 if (NextEntry
!= &PsLoadedModuleList
)
2613 /* Check if we had already mapped a section */
2616 /* Dereference and clear */
2617 ObDereferenceObject(Section
);
2621 /* Check if this was supposed to be a session load */
2624 /* It wasn't, so just return the data */
2625 *ModuleObject
= LdrEntry
;
2626 *ImageBaseAddress
= LdrEntry
->DllBase
;
2627 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2631 /* We don't support session loading yet */
2632 DPRINT1("Unsupported Session-Load!\n");
2641 /* It wasn't loaded, and we didn't have a previous attempt */
2642 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2643 KeLeaveCriticalRegion();
2646 /* Check if KD is enabled */
2647 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2649 /* FIXME: Attempt to get image from KD */
2652 /* We don't have a valid entry */
2655 /* Setup image attributes */
2656 InitializeObjectAttributes(&ObjectAttributes
,
2658 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2662 /* Open the image */
2663 Status
= ZwOpenFile(&FileHandle
,
2667 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2669 if (!NT_SUCCESS(Status
)) goto Quickie
;
2672 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2673 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2674 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2675 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2681 /* Check if this is a session-load */
2684 /* Then we only need read and execute */
2685 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2689 /* Otherwise, we can allow write access */
2690 DesiredAccess
= SECTION_ALL_ACCESS
;
2693 /* Initialize the attributes for the section */
2694 InitializeObjectAttributes(&ObjectAttributes
,
2696 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2700 /* Create the section */
2701 Status
= ZwCreateSection(&SectionHandle
,
2708 if (!NT_SUCCESS(Status
)) goto Quickie
;
2710 /* Now get the section pointer */
2711 Status
= ObReferenceObjectByHandle(SectionHandle
,
2712 SECTION_MAP_EXECUTE
,
2713 MmSectionObjectType
,
2717 ZwClose(SectionHandle
);
2718 if (!NT_SUCCESS(Status
)) goto Quickie
;
2720 /* Check if this was supposed to be a session-load */
2723 /* We don't support session loading yet */
2724 DPRINT1("Unsupported Session-Load!\n");
2728 /* Check the loader list again, we should end up in the path below */
2733 /* We don't have a valid entry */
2737 /* Load the image */
2738 Status
= MiLoadImageSection(&Section
,
2743 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
2745 /* Get the size of the driver */
2746 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
2748 /* Make sure we're not being loaded into session space */
2751 /* Check for success */
2752 if (NT_SUCCESS(Status
))
2754 /* Support large pages for drivers */
2755 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
2761 /* Dereference the section */
2762 ObDereferenceObject(Section
);
2766 /* Check for failure of the load earlier */
2767 if (!NT_SUCCESS(Status
)) goto Quickie
;
2769 /* Relocate the driver */
2770 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
2774 STATUS_CONFLICTING_ADDRESSES
,
2775 STATUS_INVALID_IMAGE_FORMAT
);
2776 if (!NT_SUCCESS(Status
)) goto Quickie
;
2779 /* Get the NT Header */
2780 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
2782 /* Calculate the size we'll need for the entry and allocate it */
2783 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2785 sizeof(UNICODE_NULL
);
2787 /* Allocate the entry */
2788 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2792 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2796 /* Setup the entry */
2797 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
2798 LdrEntry
->LoadCount
= 1;
2799 LdrEntry
->LoadedImports
= LoadedImports
;
2800 LdrEntry
->PatchInformation
= NULL
;
2802 /* Check the version */
2803 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
2804 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
2806 /* Mark this image as a native image */
2807 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
2810 /* Setup the rest of the entry */
2811 LdrEntry
->DllBase
= ModuleLoadBase
;
2812 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
2813 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
2814 LdrEntry
->SizeOfImage
= DriverSize
;
2815 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
2816 LdrEntry
->SectionPointer
= Section
;
2818 /* Now write the DLL name */
2819 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
2820 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
2821 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
2823 /* Copy and null-terminate it */
2824 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
2827 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2829 /* Now allocate the full name */
2830 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2832 sizeof(UNICODE_NULL
),
2834 if (!LdrEntry
->FullDllName
.Buffer
)
2836 /* Don't fail, just set it to zero */
2837 LdrEntry
->FullDllName
.Length
= 0;
2838 LdrEntry
->FullDllName
.MaximumLength
= 0;
2843 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
2844 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
2846 /* Copy and null-terminate */
2847 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
2850 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2854 MiProcessLoaderEntry(LdrEntry
, TRUE
);
2856 /* Resolve imports */
2857 MissingApiName
= Buffer
;
2858 Status
= MiResolveImageReferences(ModuleLoadBase
,
2864 if (!NT_SUCCESS(Status
))
2867 MiProcessLoaderEntry(LdrEntry
, FALSE
);
2869 /* Check if we need to free the name */
2870 if (LdrEntry
->FullDllName
.Buffer
)
2873 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
2876 /* Free the entry itself */
2877 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
2882 /* Update the loader entry */
2883 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
2884 LDRP_ENTRY_PROCESSED
|
2886 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2887 LdrEntry
->LoadedImports
= LoadedImports
;
2889 /* FIXME: Call driver verifier's loader function */
2891 /* Write-protect the system image */
2892 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
2894 /* Check if notifications are enabled */
2895 if (PsImageNotifyEnabled
)
2897 /* Fill out the notification data */
2898 ImageInfo
.Properties
= 0;
2899 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
2900 ImageInfo
.SystemModeImage
= TRUE
;
2901 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
2902 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
2903 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
2905 /* Send the notification */
2906 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
2909 #if defined(KDBG) || defined(_WINKD_)
2910 /* MiCacheImageSymbols doesn't detect rossym */
2913 /* Check if there's symbols */
2914 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
2917 /* Check if the system root is present */
2918 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
2919 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
2921 /* Add the system root */
2922 UnicodeTemp
= PrefixName
;
2923 UnicodeTemp
.Buffer
+= 11;
2924 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
2927 &SharedUserData
->NtSystemRoot
[2],
2932 /* Build the name */
2933 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2936 /* Setup the ansi string */
2937 RtlInitString(&AnsiTemp
, Buffer
);
2939 /* Notify the debugger */
2940 DbgLoadImageSymbols(&AnsiTemp
,
2942 (ULONG_PTR
)ZwCurrentProcess());
2943 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
2946 /* Page the driver */
2947 ASSERT(Section
== NULL
);
2948 MiEnablePagingOfDriver(LdrEntry
);
2950 /* Return pointers */
2951 *ModuleObject
= LdrEntry
;
2952 *ImageBaseAddress
= LdrEntry
->DllBase
;
2955 /* Check if we have the lock acquired */
2958 /* Release the lock */
2959 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2960 KeLeaveCriticalRegion();
2964 /* If we have a file handle, close it */
2965 if (FileHandle
) ZwClose(FileHandle
);
2967 /* Check if we had a prefix */
2968 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
2970 /* Free the name buffer and return status */
2971 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
2975 PLDR_DATA_TABLE_ENTRY
2977 MiLookupDataTableEntry(IN PVOID Address
)
2979 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
2980 PLIST_ENTRY NextEntry
;
2984 NextEntry
= PsLoadedModuleList
.Flink
;
2987 /* Get the loader entry */
2988 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2989 LDR_DATA_TABLE_ENTRY
,
2992 /* Check if the address matches */
2993 if ((Address
>= LdrEntry
->DllBase
) &&
2994 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
2995 LdrEntry
->SizeOfImage
)))
2998 FoundEntry
= LdrEntry
;
3003 NextEntry
= NextEntry
->Flink
;
3004 } while(NextEntry
!= &PsLoadedModuleList
);
3006 /* Return the entry */
3010 /* PUBLIC FUNCTIONS ***********************************************************/
3017 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3019 PMMPTE StartPte
, EndPte
;
3020 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3023 /* Get the loader entry */
3024 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3025 if (!LdrEntry
) return NULL
;
3027 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3028 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3030 /* Don't do anything, just return the base address */
3031 return LdrEntry
->DllBase
;
3034 /* Wait for active DPCs to finish before we page out the driver */
3035 KeFlushQueuedDpcs();
3037 /* Get the PTE range for the whole driver image */
3038 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3039 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3041 /* Enable paging for the PTE range */
3042 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3043 MiSetPagingOfDriver(StartPte
, EndPte
);
3045 /* Return the base address */
3046 return LdrEntry
->DllBase
;
3054 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3064 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3066 PVOID ProcAddress
= NULL
;
3067 ANSI_STRING AnsiRoutineName
;
3069 PLIST_ENTRY NextEntry
;
3070 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3071 BOOLEAN Found
= FALSE
;
3072 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3073 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3076 /* Convert routine to ansi name */
3077 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3080 if (!NT_SUCCESS(Status
)) return NULL
;
3083 KeEnterCriticalRegion();
3084 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3086 /* Loop the loaded module list */
3087 NextEntry
= PsLoadedModuleList
.Flink
;
3088 while (NextEntry
!= &PsLoadedModuleList
)
3091 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3092 LDR_DATA_TABLE_ENTRY
,
3095 /* Check if it's the kernel or HAL */
3096 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3102 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3109 /* Check if we found a valid binary */
3112 /* Find the procedure name */
3113 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3116 /* Break out if we found it or if we already tried both modules */
3117 if (ProcAddress
) break;
3118 if (Modules
== 2) break;
3122 NextEntry
= NextEntry
->Flink
;
3125 /* Release the lock */
3126 ExReleaseResourceLite(&PsLoadedModuleResource
);
3127 KeLeaveCriticalRegion();
3129 /* Free the string and return */
3130 RtlFreeAnsiString(&AnsiRoutineName
);