2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * ReactOS Portable Systems Group
10 /* INCLUDES *******************************************************************/
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 /* GCC's incompetence strikes again */
22 sprintf_nt(IN PCHAR Buffer
,
28 vsprintf(Buffer
, Format
, ap
);
32 /* GLOBALS ********************************************************************/
34 LIST_ENTRY PsLoadedModuleList
;
35 LIST_ENTRY MmLoadedUserImageList
;
36 KSPIN_LOCK PsLoadedModuleSpinLock
;
37 ERESOURCE PsLoadedModuleResource
;
38 ULONG_PTR PsNtosImageBase
;
39 KMUTANT MmSystemLoadLock
;
41 PFN_NUMBER MmTotalSystemDriverPages
;
43 PVOID MmUnloadedDrivers
;
44 PVOID MmLastUnloadedDrivers
;
46 BOOLEAN MmMakeLowMemory
;
47 BOOLEAN MmEnforceWriteProtection
= TRUE
;
49 PMMPTE MiKernelResourceStartPte
, MiKernelResourceEndPte
;
50 ULONG_PTR ExPoolCodeStart
, ExPoolCodeEnd
, MmPoolCodeStart
, MmPoolCodeEnd
;
51 ULONG_PTR MmPteCodeStart
, MmPteCodeEnd
;
53 /* FUNCTIONS ******************************************************************/
57 MiCacheImageSymbols(IN PVOID BaseAddress
)
60 PVOID DebugDirectory
= NULL
;
63 /* Make sure it's safe to access the image */
66 /* Get the debug directory */
67 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
69 IMAGE_DIRECTORY_ENTRY_DEBUG
,
72 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
78 /* Return the directory */
79 return DebugDirectory
;
84 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
86 IN PUNICODE_STRING FileName
,
87 IN BOOLEAN SessionLoad
,
88 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
90 PROS_SECTION_OBJECT Section
= *SectionPtr
;
96 LARGE_INTEGER SectionOffset
= {{0, 0}};
97 BOOLEAN LoadSymbols
= FALSE
;
99 PMMPTE PointerPte
, LastPte
;
104 /* Detect session load */
108 DPRINT1("Session loading not yet supported!\n");
112 /* Not session load, shouldn't have an entry */
113 ASSERT(LdrEntry
== NULL
);
115 /* Attach to the system process */
116 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
118 /* Check if we need to load symbols */
119 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
123 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
127 Process
= PsGetCurrentProcess();
128 Status
= MmMapViewOfSection(Section
,
139 /* Re-enable the flag */
140 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
142 /* Check if we failed with distinguished status code */
143 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
145 /* Change it to something more generic */
146 Status
= STATUS_INVALID_IMAGE_FORMAT
;
149 /* Now check if we failed */
150 if (!NT_SUCCESS(Status
))
152 /* Detach and return */
153 KeUnstackDetachProcess(&ApcState
);
157 /* Reserve system PTEs needed */
158 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
159 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
160 if (!PointerPte
) return STATUS_INSUFFICIENT_RESOURCES
;
162 /* New driver base */
163 LastPte
= PointerPte
+ PteCount
;
164 DriverBase
= MiPteToAddress(PointerPte
);
166 /* The driver is here */
167 *ImageBase
= DriverBase
;
168 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName
, DriverBase
, PteCount
);
170 /* Loop the new driver PTEs */
171 TempPte
= ValidKernelPte
;
172 while (PointerPte
< LastPte
)
174 /* Allocate a page */
175 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
179 if (FileName
->Buffer
)
181 pos
= wcsrchr(FileName
->Buffer
, '\\');
182 len
= wcslen(pos
) * sizeof(WCHAR
);
183 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
186 TempPte
.u
.Hard
.PageFrameNumber
= MiAllocatePfn(PointerPte
, MM_EXECUTE
);
189 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
196 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
198 /* Now unmap the view */
199 Status
= MmUnmapViewOfSection(Process
, Base
);
200 ASSERT(NT_SUCCESS(Status
));
202 /* Detach and return status */
203 KeUnstackDetachProcess(&ApcState
);
209 MiLocateExportName(IN PVOID DllBase
,
213 PUSHORT OrdinalTable
;
214 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
215 LONG Low
= 0, Mid
= 0, High
, Ret
;
222 /* Get the export directory */
223 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
225 IMAGE_DIRECTORY_ENTRY_EXPORT
,
227 if (!ExportDirectory
) return NULL
;
229 /* Setup name tables */
230 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
231 ExportDirectory
->AddressOfNames
);
232 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
233 ExportDirectory
->AddressOfNameOrdinals
);
235 /* Do a binary search */
236 High
= ExportDirectory
->NumberOfNames
- 1;
239 /* Get new middle value */
240 Mid
= (Low
+ High
) >> 1;
243 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
261 /* Check if we couldn't find it */
262 if (High
< Low
) return NULL
;
264 /* Otherwise, this is the ordinal */
265 Ordinal
= OrdinalTable
[Mid
];
267 /* Resolve the address and write it */
268 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
269 ExportDirectory
->AddressOfFunctions
);
270 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
272 /* Check if the function is actually a forwarder */
273 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
274 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
286 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
287 IN PLIST_ENTRY ListHead
)
289 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
290 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
291 PMM_DLL_INITIALIZE DllInit
;
292 UNICODE_STRING RegPath
, ImportName
;
295 /* Try to see if the image exports a DllInitialize routine */
296 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
298 if (!DllInit
) return STATUS_SUCCESS
;
300 /* Do a temporary copy of BaseDllName called ImportName
301 * because we'll alter the length of the string
303 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
304 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
305 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
307 /* Obtain the path to this dll's service in the registry */
308 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
309 ImportName
.Length
+ sizeof(UNICODE_NULL
);
310 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
311 RegPath
.MaximumLength
,
314 /* Check if this allocation was unsuccessful */
315 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
317 /* Build and append the service name itself */
318 RegPath
.Length
= ServicesKeyName
.Length
;
319 RtlCopyMemory(RegPath
.Buffer
,
320 ServicesKeyName
.Buffer
,
321 ServicesKeyName
.Length
);
323 /* Check if there is a dot in the filename */
324 if (wcschr(ImportName
.Buffer
, L
'.'))
326 /* Remove the extension */
327 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
328 ImportName
.Buffer
) * sizeof(WCHAR
);
331 /* Append service name (the basename without extension) */
332 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
334 /* Now call the DllInit func */
335 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
336 Status
= DllInit(&RegPath
);
339 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
341 /* Return status value which DllInitialize returned */
347 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
353 /* Get the unload routine */
354 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
355 if (!Func
) return FALSE
;
357 /* Call it and check for success */
359 if (!NT_SUCCESS(Status
)) return FALSE
;
361 /* Lie about the load count so we can unload the image */
362 ASSERT(LdrEntry
->LoadCount
== 0);
363 LdrEntry
->LoadCount
= 1;
365 /* Unload it and return true */
366 MmUnloadSystemImage(LdrEntry
);
372 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
375 LOAD_IMPORTS SingleEntry
;
376 PLDR_DATA_TABLE_ENTRY LdrEntry
;
377 PVOID CurrentImports
;
380 /* Check if there's no imports or if we're a boot driver */
381 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
382 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
383 (ImportList
->Count
== 0))
385 /* Then there's nothing to do */
386 return STATUS_SUCCESS
;
389 /* Check for single-entry */
390 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
393 SingleEntry
.Count
= 1;
394 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
396 /* Use this as the import list */
397 ImportList
= &SingleEntry
;
400 /* Loop the import list */
401 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
404 LdrEntry
= ImportList
->Entry
[i
];
405 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
407 /* Skip boot loaded images */
408 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
410 /* Dereference the entry */
411 ASSERT(LdrEntry
->LoadCount
>= 1);
412 if (!--LdrEntry
->LoadCount
)
414 /* Save the import data in case unload fails */
415 CurrentImports
= LdrEntry
->LoadedImports
;
417 /* This is the last entry */
418 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
419 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
421 /* Unloading worked, parse this DLL's imports too */
422 MiDereferenceImports(CurrentImports
);
424 /* Check if we had valid imports */
425 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
426 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
427 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
430 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
435 /* Unload failed, restore imports */
436 LdrEntry
->LoadedImports
= CurrentImports
;
442 return STATUS_SUCCESS
;
447 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
451 /* Check if there's no imports or we're a boot driver or only one entry */
452 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
453 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
454 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
460 /* Otherwise, free the import list */
461 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
462 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
467 MiFindExportedRoutineByName(IN PVOID DllBase
,
468 IN PANSI_STRING ExportName
)
471 PUSHORT OrdinalTable
;
472 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
473 LONG Low
= 0, Mid
= 0, High
, Ret
;
480 /* Get the export directory */
481 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
483 IMAGE_DIRECTORY_ENTRY_EXPORT
,
485 if (!ExportDirectory
) return NULL
;
487 /* Setup name tables */
488 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
489 ExportDirectory
->AddressOfNames
);
490 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
491 ExportDirectory
->AddressOfNameOrdinals
);
493 /* Do a binary search */
494 High
= ExportDirectory
->NumberOfNames
- 1;
497 /* Get new middle value */
498 Mid
= (Low
+ High
) >> 1;
501 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
519 /* Check if we couldn't find it */
520 if (High
< Low
) return NULL
;
522 /* Otherwise, this is the ordinal */
523 Ordinal
= OrdinalTable
[Mid
];
525 /* Validate the ordinal */
526 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
528 /* Resolve the address and write it */
529 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
530 ExportDirectory
->AddressOfFunctions
);
531 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
534 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
535 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
541 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
546 /* Acquire module list lock */
547 KeEnterCriticalRegion();
548 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
550 /* Acquire the spinlock too as we will insert or remove the entry */
551 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
553 /* Insert or remove from the list */
554 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
555 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
558 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
559 ExReleaseResourceLite(&PsLoadedModuleResource
);
560 KeLeaveCriticalRegion();
566 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
571 ULONG_PTR OldBaseTop
, Delta
;
572 PLDR_DATA_TABLE_ENTRY LdrEntry
;
573 PLIST_ENTRY NextEntry
;
576 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
577 // since a real version of Windows would fail at this point, but they seem
578 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
579 // a feature which isn't even used by Windows. Priorities, priorities...
580 // Please note that Microsoft WDK EULA and license prohibits using
581 // the information contained within it for the generation of "non-Windows"
582 // drivers, which is precisely what LD will generate, since an LD driver
583 // will not load on Windows.
585 #ifdef _WORKING_LINKER_
588 PULONG_PTR ImageThunk
;
589 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
591 /* Calculate the top and delta */
592 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
593 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
595 /* Loop the loader block */
596 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
597 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
598 NextEntry
= NextEntry
->Flink
)
600 /* Get the loader entry */
601 LdrEntry
= CONTAINING_RECORD(NextEntry
,
602 LDR_DATA_TABLE_ENTRY
,
604 #ifdef _WORKING_LINKER_
606 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
608 IMAGE_DIRECTORY_ENTRY_IAT
,
610 if (!ImageThunk
) continue;
612 /* Make sure we have an IAT */
613 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
614 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
616 /* Check if it's within this module */
617 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
620 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
621 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
622 *ImageThunk
+= Delta
;
626 /* Get the import table */
627 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
629 IMAGE_DIRECTORY_ENTRY_IMPORT
,
631 if (!ImportDescriptor
) continue;
633 /* Make sure we have an IAT */
634 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
635 while ((ImportDescriptor
->Name
) &&
636 (ImportDescriptor
->OriginalFirstThunk
))
638 /* Get the image thunk */
639 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
640 ImportDescriptor
->FirstThunk
);
643 /* Check if it's within this module */
644 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
647 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
648 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
649 *ImageThunk
+= Delta
;
652 /* Go to the next thunk */
656 /* Go to the next import */
665 MiSnapThunk(IN PVOID DllBase
,
667 IN PIMAGE_THUNK_DATA Name
,
668 IN PIMAGE_THUNK_DATA Address
,
669 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
671 IN BOOLEAN SnapForwarder
,
672 OUT PCHAR
*MissingApi
)
677 PUSHORT OrdinalTable
;
678 PIMAGE_IMPORT_BY_NAME NameImport
;
680 ULONG Low
= 0, Mid
= 0, High
;
683 PCHAR MissingForwarder
;
684 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
687 UNICODE_STRING ForwarderName
;
688 PLIST_ENTRY NextEntry
;
689 PLDR_DATA_TABLE_ENTRY LdrEntry
;
690 ULONG ForwardExportSize
;
691 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
692 PIMAGE_IMPORT_BY_NAME ForwardName
;
693 SIZE_T ForwardLength
;
694 IMAGE_THUNK_DATA ForwardThunk
;
697 /* Check if this is an ordinal */
698 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
699 if ((IsOrdinal
) && !(SnapForwarder
))
701 /* Get the ordinal number and set it as missing */
702 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
703 ExportDirectory
->Base
);
704 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
708 /* Get the VA if we don't have to snap */
709 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
710 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
712 /* Copy the procedure name */
713 RtlStringCbCopyA(*MissingApi
,
714 MAXIMUM_FILENAME_LENGTH
,
715 (PCHAR
)&NameImport
->Name
[0]);
717 /* Setup name tables */
718 DPRINT("Import name: %s\n", NameImport
->Name
);
719 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
720 ExportDirectory
->AddressOfNames
);
721 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
722 ExportDirectory
->AddressOfNameOrdinals
);
724 /* Get the hint and check if it's valid */
725 Hint
= NameImport
->Hint
;
726 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
727 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
729 /* We have a match, get the ordinal number from here */
730 Ordinal
= OrdinalTable
[Hint
];
734 /* Do a binary search */
735 High
= ExportDirectory
->NumberOfNames
- 1;
738 /* Get new middle value */
739 Mid
= (Low
+ High
) >> 1;
742 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
760 /* Check if we couldn't find it */
763 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
764 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
767 /* Otherwise, this is the ordinal */
768 Ordinal
= OrdinalTable
[Mid
];
772 /* Check if the ordinal is invalid */
773 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
776 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
780 /* In case the forwarder is missing */
781 MissingForwarder
= NameBuffer
;
783 /* Resolve the address and write it */
784 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
785 ExportDirectory
->AddressOfFunctions
);
786 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
788 /* Assume success from now on */
789 Status
= STATUS_SUCCESS
;
791 /* Check if the function is actually a forwarder */
792 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
793 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
795 /* Now assume failure in case the forwarder doesn't exist */
796 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
798 /* Build the forwarder name */
799 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
800 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
803 DllName
.MaximumLength
= DllName
.Length
;
806 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
810 /* We failed, just return an error */
814 /* Loop the module list */
815 NextEntry
= PsLoadedModuleList
.Flink
;
816 while (NextEntry
!= &PsLoadedModuleList
)
818 /* Get the loader entry */
819 LdrEntry
= CONTAINING_RECORD(NextEntry
,
820 LDR_DATA_TABLE_ENTRY
,
823 /* Check if it matches */
824 if (RtlPrefixString((PSTRING
)&ForwarderName
,
825 (PSTRING
)&LdrEntry
->BaseDllName
,
828 /* Get the forwarder export directory */
829 ForwardExportDirectory
=
830 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
832 IMAGE_DIRECTORY_ENTRY_EXPORT
,
834 if (!ForwardExportDirectory
) break;
836 /* Allocate a name entry */
837 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
839 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
840 sizeof(*ForwardName
) +
843 if (!ForwardName
) break;
846 RtlCopyMemory(&ForwardName
->Name
[0],
847 DllName
.Buffer
+ DllName
.Length
,
849 ForwardName
->Hint
= 0;
851 /* Set the new address */
852 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
854 /* Snap the forwarder */
855 Status
= MiSnapThunk(LdrEntry
->DllBase
,
859 ForwardExportDirectory
,
864 /* Free the forwarder name and set the thunk */
865 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
866 Address
->u1
= ForwardThunk
.u1
;
870 /* Go to the next entry */
871 NextEntry
= NextEntry
->Flink
;
875 RtlFreeUnicodeString(&ForwarderName
);
885 MmUnloadSystemImage(IN PVOID ImageHandle
)
887 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
888 PVOID BaseAddress
= LdrEntry
->DllBase
;
891 BOOLEAN HadEntry
= FALSE
;
893 /* Acquire the loader lock */
894 KeEnterCriticalRegion();
895 KeWaitForSingleObject(&MmSystemLoadLock
,
901 /* Check if this driver was loaded at boot and didn't get imports parsed */
902 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
904 /* We should still be alive */
905 ASSERT(LdrEntry
->LoadCount
!= 0);
906 LdrEntry
->LoadCount
--;
908 /* Check if we're still loaded */
909 if (LdrEntry
->LoadCount
) goto Done
;
911 /* We should cleanup... are symbols loaded */
912 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
914 /* Create the ANSI name */
915 Status
= RtlUnicodeStringToAnsiString(&TempName
,
916 &LdrEntry
->BaseDllName
,
918 if (NT_SUCCESS(Status
))
920 /* Unload the symbols */
921 DbgUnLoadImageSymbols(&TempName
,
923 (ULONG_PTR
)ZwCurrentProcess());
924 RtlFreeAnsiString(&TempName
);
928 /* FIXME: Free the driver */
929 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
930 //MmFreeSection(LdrEntry->DllBase);
932 /* Check if we're linked in */
933 if (LdrEntry
->InLoadOrderLinks
.Flink
)
936 MiProcessLoaderEntry(LdrEntry
, FALSE
);
940 /* Dereference and clear the imports */
941 MiDereferenceImports(LdrEntry
->LoadedImports
);
942 MiClearImports(LdrEntry
);
944 /* Check if the entry needs to go away */
947 /* Check if it had a name */
948 if (LdrEntry
->FullDllName
.Buffer
)
951 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
954 /* Check if we had a section */
955 if (LdrEntry
->SectionPointer
)
958 ObDereferenceObject(LdrEntry
->SectionPointer
);
962 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
965 /* Release the system lock and return */
967 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
968 KeLeaveCriticalRegion();
969 return STATUS_SUCCESS
;
974 MiResolveImageReferences(IN PVOID ImageBase
,
975 IN PUNICODE_STRING ImageFileDirectory
,
976 IN PUNICODE_STRING NamePrefix OPTIONAL
,
977 OUT PCHAR
*MissingApi
,
978 OUT PWCHAR
*MissingDriver
,
979 OUT PLOAD_IMPORTS
*LoadImports
)
981 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
982 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
983 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
984 PLOAD_IMPORTS LoadedImports
, NewImports
;
985 ULONG GdiLink
, NormalLink
, i
;
986 BOOLEAN ReferenceNeeded
, Loaded
;
987 ANSI_STRING TempString
;
988 UNICODE_STRING NameString
, DllName
;
989 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
990 PVOID ImportBase
, DllBase
;
991 PLIST_ENTRY NextEntry
;
992 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
994 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
996 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
997 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
999 /* Assume no imports */
1000 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1002 /* Get the import descriptor */
1003 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1005 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1007 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1009 /* Loop all imports to count them */
1010 for (CurrentImport
= ImportDescriptor
;
1011 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1018 /* Make sure we have non-zero imports */
1021 /* Calculate and allocate the list we'll need */
1022 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1023 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1029 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1030 LoadedImports
->Count
= ImportCount
;
1036 LoadedImports
= NULL
;
1039 /* Reset the import count and loop descriptors again */
1040 ImportCount
= GdiLink
= NormalLink
= 0;
1041 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1044 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1046 /* Check if this is a GDI driver */
1048 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1050 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1051 NormalLink
= NormalLink
|
1052 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1053 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1054 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1055 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1057 /* Check if this is a valid GDI driver */
1058 if ((GdiLink
) && (NormalLink
))
1060 /* It's not, it's importing stuff it shouldn't be! */
1061 MiDereferenceImports(LoadedImports
);
1062 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1063 return STATUS_PROCEDURE_NOT_FOUND
;
1066 /* Check for user-mode printer or video card drivers, which don't belong */
1067 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1068 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1069 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1070 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1071 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1072 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1074 /* This is not kernel code */
1075 MiDereferenceImports(LoadedImports
);
1076 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1077 return STATUS_PROCEDURE_NOT_FOUND
;
1080 /* Check if this is a "core" import, which doesn't get referenced */
1081 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1082 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1083 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1085 /* Don't reference this */
1086 ReferenceNeeded
= FALSE
;
1090 /* Reference these modules */
1091 ReferenceNeeded
= TRUE
;
1094 /* Now setup a unicode string for the import */
1095 RtlInitAnsiString(&TempString
, ImportName
);
1096 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1097 if (!NT_SUCCESS(Status
))
1100 MiDereferenceImports(LoadedImports
);
1101 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1105 /* We don't support name prefixes yet */
1106 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1108 /* Remember that we haven't loaded the import at this point */
1113 /* Loop the driver list */
1114 NextEntry
= PsLoadedModuleList
.Flink
;
1115 while (NextEntry
!= &PsLoadedModuleList
)
1117 /* Get the loader entry and compare the name */
1118 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1119 LDR_DATA_TABLE_ENTRY
,
1121 if (RtlEqualUnicodeString(&NameString
,
1122 &LdrEntry
->BaseDllName
,
1125 /* Get the base address */
1126 ImportBase
= LdrEntry
->DllBase
;
1128 /* Check if we haven't loaded yet, and we need references */
1129 if (!(Loaded
) && (ReferenceNeeded
))
1131 /* Make sure we're not already loading */
1132 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1134 /* Increase the load count */
1135 LdrEntry
->LoadCount
++;
1139 /* Done, break out */
1143 /* Go to the next entry */
1144 NextEntry
= NextEntry
->Flink
;
1147 /* Check if we haven't loaded the import yet */
1150 /* Setup the import DLL name */
1151 DllName
.MaximumLength
= NameString
.Length
+
1152 ImageFileDirectory
->Length
+
1153 sizeof(UNICODE_NULL
);
1154 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1155 DllName
.MaximumLength
,
1159 /* Setup the base length and copy it */
1160 DllName
.Length
= ImageFileDirectory
->Length
;
1161 RtlCopyMemory(DllName
.Buffer
,
1162 ImageFileDirectory
->Buffer
,
1163 ImageFileDirectory
->Length
);
1165 /* Now add the import name and null-terminate it */
1166 RtlAppendUnicodeStringToString(&DllName
,
1168 DllName
.Buffer
[DllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1170 /* Load the image */
1171 Status
= MmLoadSystemImage(&DllName
,
1177 if (NT_SUCCESS(Status
))
1179 /* We can free the DLL Name */
1180 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1184 /* Fill out the information for the error */
1185 *MissingDriver
= DllName
.Buffer
;
1186 *(PULONG
)MissingDriver
|= 1;
1192 /* We're out of resources */
1193 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1196 /* Check if we're OK until now */
1197 if (NT_SUCCESS(Status
))
1199 /* We're now loaded */
1203 ASSERT(DllBase
= DllEntry
->DllBase
);
1205 /* Call the initialization routines */
1206 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1207 if (!NT_SUCCESS(Status
))
1209 /* We failed, unload the image */
1210 MmUnloadSystemImage(DllEntry
);
1216 /* Check if we failed by here */
1217 if (!NT_SUCCESS(Status
))
1219 /* Cleanup and return */
1220 RtlFreeUnicodeString(&NameString
);
1221 MiDereferenceImports(LoadedImports
);
1222 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1226 /* Loop again to make sure that everything is OK */
1230 /* Check if we're support to reference this import */
1231 if ((ReferenceNeeded
) && (LoadedImports
))
1233 /* Make sure we're not already loading */
1234 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1237 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1242 /* Free the import name */
1243 RtlFreeUnicodeString(&NameString
);
1245 /* Set the missing driver name and get the export directory */
1246 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1247 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1249 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1251 if (!ExportDirectory
)
1253 /* Cleanup and return */
1254 MiDereferenceImports(LoadedImports
);
1255 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1256 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1257 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1260 /* Make sure we have an IAT */
1261 if (ImportDescriptor
->OriginalFirstThunk
)
1263 /* Get the first thunks */
1264 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1265 ImportDescriptor
->OriginalFirstThunk
);
1266 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1267 ImportDescriptor
->FirstThunk
);
1270 while (OrigThunk
->u1
.AddressOfData
)
1273 Status
= MiSnapThunk(ImportBase
,
1281 if (!NT_SUCCESS(Status
))
1283 /* Cleanup and return */
1284 MiDereferenceImports(LoadedImports
);
1285 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1289 /* Reset the buffer */
1290 *MissingApi
= MissingApiBuffer
;
1294 /* Go to the next import */
1298 /* Check if we have an import list */
1301 /* Reset the count again, and loop entries */
1303 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1305 if (LoadedImports
->Entry
[i
])
1307 /* Got an entry, OR it with 1 in case it's the single entry */
1308 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1309 MM_SYSLDR_SINGLE_ENTRY
);
1314 /* Check if we had no imports */
1317 /* Free the list and set it to no imports */
1318 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1319 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1321 else if (ImportCount
== 1)
1323 /* Just one entry, we can free the table and only use our entry */
1324 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1325 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1327 else if (ImportCount
!= LoadedImports
->Count
)
1329 /* Allocate a new list */
1330 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1331 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1337 NewImports
->Count
= 0;
1339 /* Loop all the imports */
1340 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1342 /* Make sure it's valid */
1343 if (LoadedImports
->Entry
[i
])
1346 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1347 NewImports
->Count
++;
1351 /* Free the old copy */
1352 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1353 LoadedImports
= NewImports
;
1357 /* Return the list */
1358 *LoadImports
= LoadedImports
;
1361 /* Return success */
1362 return STATUS_SUCCESS
;
1368 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1370 PLIST_ENTRY NextEntry
;
1372 PIMAGE_NT_HEADERS NtHeader
;
1373 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1374 PIMAGE_FILE_HEADER FileHeader
;
1375 BOOLEAN ValidRelocs
;
1376 PIMAGE_DATA_DIRECTORY DataDirectory
;
1377 PVOID DllBase
, NewImageAddress
;
1379 PMMPTE PointerPte
, StartPte
, LastPte
;
1382 MMPTE TempPte
, OldPte
;
1384 /* Loop driver list */
1385 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1386 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1387 NextEntry
= NextEntry
->Flink
)
1389 /* Get the loader entry and NT header */
1390 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1391 LDR_DATA_TABLE_ENTRY
,
1393 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1396 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1398 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1399 &LdrEntry
->FullDllName
);
1401 /* Get the first PTE and the number of PTEs we'll need */
1402 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1403 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1404 LastPte
= StartPte
+ PteCount
;
1408 while (PointerPte
< LastPte
)
1411 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1412 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1413 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1414 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1418 /* Skip kernel and HAL */
1419 /* ROS HACK: Skip BOOTVID/KDCOM too */
1421 if (i
<= 4) continue;
1423 /* Skip non-drivers */
1424 if (!NtHeader
) continue;
1426 /* Get the file header and make sure we can relocate */
1427 FileHeader
= &NtHeader
->FileHeader
;
1428 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1429 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1430 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1432 /* Everything made sense until now, check the relocation section too */
1433 DataDirectory
= &NtHeader
->OptionalHeader
.
1434 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1435 if (!DataDirectory
->VirtualAddress
)
1437 /* We don't really have relocations */
1438 ValidRelocs
= FALSE
;
1442 /* Make sure the size is valid */
1443 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1444 LdrEntry
->SizeOfImage
)
1446 /* They're not, skip */
1450 /* We have relocations */
1454 /* Remember the original address */
1455 DllBase
= LdrEntry
->DllBase
;
1458 PointerPte
= StartPte
;
1459 while (PointerPte
< LastPte
)
1461 /* Mark the page modified in the PFN database */
1462 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1463 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1464 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1465 Pfn1
->u3
.e1
.Modified
= TRUE
;
1471 /* Now reserve system PTEs for the image */
1472 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1475 /* Shouldn't happen */
1476 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1480 /* This is the new virtual address for the module */
1481 LastPte
= PointerPte
+ PteCount
;
1482 NewImageAddress
= MiPteToAddress(PointerPte
);
1485 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1486 ASSERT(ExpInitializationPhase
== 0);
1488 /* Loop the new driver PTEs */
1489 TempPte
= ValidKernelPte
;
1490 while (PointerPte
< LastPte
)
1492 /* Copy the old data */
1494 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1496 /* Set page number from the loader's memory */
1497 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1500 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1507 /* Update position */
1508 PointerPte
-= PteCount
;
1511 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1513 /* Set the image base to the address where the loader put it */
1514 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1516 /* Check if we had relocations */
1519 /* Relocate the image */
1520 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1524 STATUS_CONFLICTING_ADDRESSES
,
1525 STATUS_INVALID_IMAGE_FORMAT
);
1526 if (!NT_SUCCESS(Status
))
1528 /* This shouldn't happen */
1529 DPRINT1("Relocations failed!\n");
1534 /* Update the loader entry */
1535 LdrEntry
->DllBase
= NewImageAddress
;
1537 /* Update the thunks */
1538 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1539 MiUpdateThunks(LoaderBlock
,
1542 LdrEntry
->SizeOfImage
);
1544 /* Update the loader entry */
1545 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1546 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1547 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1548 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1550 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1557 MiBuildImportsForBootDrivers(VOID
)
1559 PLIST_ENTRY NextEntry
, NextEntry2
;
1560 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1561 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1562 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1563 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1564 PLOAD_IMPORTS LoadedImports
;
1565 ULONG LoadedImportsSize
, ImportSize
;
1566 PULONG_PTR ImageThunk
;
1567 ULONG_PTR DllBase
, DllEnd
;
1568 ULONG Modules
= 0, i
, j
= 0;
1569 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1571 /* Initialize variables */
1572 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1574 /* Loop the loaded module list... we are early enough that no lock is needed */
1575 NextEntry
= PsLoadedModuleList
.Flink
;
1576 while (NextEntry
!= &PsLoadedModuleList
)
1579 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1580 LDR_DATA_TABLE_ENTRY
,
1583 /* Check if it's the kernel or HAL */
1584 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1587 KernelEntry
= LdrEntry
;
1589 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1592 HalEntry
= LdrEntry
;
1595 /* Check if this is a driver DLL */
1596 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1598 /* Check if this is the HAL or kernel */
1599 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1601 /* Add a reference */
1602 LdrEntry
->LoadCount
= 1;
1606 /* No referencing needed */
1607 LdrEntry
->LoadCount
= 0;
1612 /* No referencing needed */
1613 LdrEntry
->LoadCount
= 0;
1616 /* Remember this came from the loader */
1617 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1620 NextEntry
= NextEntry
->Flink
;
1624 /* We must have at least found the kernel and HAL */
1625 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1627 /* Allocate the list */
1628 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1629 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1631 /* Loop the loaded module list again */
1632 NextEntry
= PsLoadedModuleList
.Flink
;
1633 while (NextEntry
!= &PsLoadedModuleList
)
1636 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1637 LDR_DATA_TABLE_ENTRY
,
1639 #ifdef _WORKING_LOADER_
1640 /* Get its imports */
1641 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1643 IMAGE_DIRECTORY_ENTRY_IAT
,
1647 /* Get its imports */
1648 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1650 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1652 if (!ImportDescriptor
)
1656 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1657 NextEntry
= NextEntry
->Flink
;
1661 /* Clear the list and count the number of IAT thunks */
1662 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1663 #ifdef _WORKING_LOADER_
1664 ImportSize
/= sizeof(ULONG_PTR
);
1666 /* Scan the thunks */
1667 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1669 DllBase
= DllEnd
= i
= 0;
1670 while ((ImportDescriptor
->Name
) &&
1671 (ImportDescriptor
->OriginalFirstThunk
))
1673 /* Get the image thunk */
1674 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1675 ImportDescriptor
->FirstThunk
);
1679 /* Do we already have an address? */
1682 /* Is the thunk in the same address? */
1683 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1685 /* Skip it, we already have a reference for it */
1686 ASSERT(EntryArray
[j
]);
1692 /* Loop the loaded module list to locate this address owner */
1694 NextEntry2
= PsLoadedModuleList
.Flink
;
1695 while (NextEntry2
!= &PsLoadedModuleList
)
1698 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1699 LDR_DATA_TABLE_ENTRY
,
1702 /* Get the address range for this module */
1703 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1704 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1706 /* Check if this IAT entry matches it */
1707 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1710 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1711 EntryArray
[j
] = LdrEntry2
;
1715 /* Keep searching */
1716 NextEntry2
= NextEntry2
->Flink
;
1720 /* Do we have a thunk outside the range? */
1721 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1726 /* Should not be happening */
1727 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1728 LdrEntry
, ImageThunk
, *ImageThunk
);
1732 /* Reset if we hit this */
1735 #ifndef _WORKING_LOADER_
1744 /* Now scan how many imports we really have */
1745 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1747 /* Skip HAL and kernel */
1748 if ((EntryArray
[i
]) &&
1749 (EntryArray
[i
] != HalEntry
) &&
1750 (EntryArray
[i
] != KernelEntry
))
1752 /* A valid reference */
1753 LastEntry
= EntryArray
[i
];
1758 /* Do we have any imports after all? */
1762 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1764 else if (ImportSize
== 1)
1766 /* A single entry import */
1767 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
1768 LastEntry
->LoadCount
++;
1772 /* We need an import table */
1773 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
1774 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1777 ASSERT(LoadedImports
);
1779 /* Save the count */
1780 LoadedImports
->Count
= ImportSize
;
1782 /* Now copy all imports */
1783 for (i
= 0, j
= 0; i
< Modules
; i
++)
1785 /* Skip HAL and kernel */
1786 if ((EntryArray
[i
]) &&
1787 (EntryArray
[i
] != HalEntry
) &&
1788 (EntryArray
[i
] != KernelEntry
))
1790 /* A valid reference */
1791 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
1792 LoadedImports
->Entry
[j
] = EntryArray
[i
];
1793 EntryArray
[i
]->LoadCount
++;
1798 /* Should had as many entries as we expected */
1799 ASSERT(j
== ImportSize
);
1800 LdrEntry
->LoadedImports
= LoadedImports
;
1804 NextEntry
= NextEntry
->Flink
;
1807 /* Free the initial array */
1808 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
1810 /* FIXME: Might not need to keep the HAL/Kernel imports around */
1812 /* Kernel and HAL are loaded at boot */
1813 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1814 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1816 /* All worked well */
1817 return STATUS_SUCCESS
;
1823 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1826 PIMAGE_NT_HEADERS NtHeaders
;
1827 PIMAGE_SECTION_HEADER SectionHeader
;
1828 ULONG Sections
, Size
;
1830 /* Get the kernel section header */
1831 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1832 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
1833 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
1835 /* Loop all the sections */
1836 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1839 /* Grab the size of the section */
1840 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
1842 /* Check for .RSRC section */
1843 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
1845 /* Remember the PTEs so we can modify them later */
1846 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
1847 SectionHeader
->VirtualAddress
);
1848 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
1849 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
1851 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
1853 /* POOLCODE vs. POOLMI */
1854 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
1856 /* Found Ex* Pool code */
1857 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1858 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1860 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
1862 /* Found Mm* Pool code */
1863 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1864 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1867 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
1868 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
1870 /* Found MISYSPTE (Mm System PTE code)*/
1871 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1872 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
1884 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1886 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1887 PLIST_ENTRY ListHead
, NextEntry
;
1890 /* Setup the loaded module list and locks */
1891 ExInitializeResourceLite(&PsLoadedModuleResource
);
1892 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1893 InitializeListHead(&PsLoadedModuleList
);
1895 /* Get loop variables and the kernel entry */
1896 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1897 NextEntry
= ListHead
->Flink
;
1898 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1899 LDR_DATA_TABLE_ENTRY
,
1901 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1903 /* Locate resource section, pool code, and system pte code */
1904 MiLocateKernelSections(LdrEntry
);
1906 /* Loop the loader block */
1907 while (NextEntry
!= ListHead
)
1909 /* Get the loader entry */
1910 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1911 LDR_DATA_TABLE_ENTRY
,
1914 /* FIXME: ROS HACK. Make sure this is a driver */
1915 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1917 /* Skip this entry */
1918 NextEntry
= NextEntry
->Flink
;
1922 /* Calculate the size we'll need and allocate a copy */
1923 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1924 LdrEntry
->BaseDllName
.MaximumLength
+
1925 sizeof(UNICODE_NULL
);
1926 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1927 if (!NewEntry
) return FALSE
;
1929 /* Copy the entry over */
1930 *NewEntry
= *LdrEntry
;
1932 /* Allocate the name */
1933 NewEntry
->FullDllName
.Buffer
=
1934 ExAllocatePoolWithTag(PagedPool
,
1935 LdrEntry
->FullDllName
.MaximumLength
+
1936 sizeof(UNICODE_NULL
),
1938 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1940 /* Set the base name */
1941 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1943 /* Copy the full and base name */
1944 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1945 LdrEntry
->FullDllName
.Buffer
,
1946 LdrEntry
->FullDllName
.MaximumLength
);
1947 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1948 LdrEntry
->BaseDllName
.Buffer
,
1949 LdrEntry
->BaseDllName
.MaximumLength
);
1951 /* Null-terminate the base name */
1952 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1953 sizeof(WCHAR
)] = UNICODE_NULL
;
1955 /* Insert the entry into the list */
1956 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1957 NextEntry
= NextEntry
->Flink
;
1960 /* Build the import lists for the boot drivers */
1961 MiBuildImportsForBootDrivers();
1969 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
1970 IN OUT PVOID
*ImageBaseAddress
,
1971 IN PUNICODE_STRING BaseImageName
,
1972 IN BOOLEAN BootDriver
)
1974 PLIST_ENTRY NextEntry
;
1975 BOOLEAN DriverFound
= FALSE
;
1976 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
1977 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
1978 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
1981 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
1982 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
1985 /* Make sure there's enough system PTEs for a large page driver */
1986 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
1991 /* This happens if the registry key had a "*" (wildcard) in it */
1992 if (MiLargePageAllDrivers
== 0)
1994 /* It didn't, so scan the list */
1995 NextEntry
= MiLargePageDriverList
.Flink
;
1996 while (NextEntry
!= &MiLargePageDriverList
)
1998 /* Check if the driver name matches */
1999 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2000 MI_LARGE_PAGE_DRIVER_ENTRY
,
2002 if (RtlEqualUnicodeString(BaseImageName
,
2003 &LargePageDriverEntry
->BaseName
,
2006 /* Enable large pages for this driver */
2012 NextEntry
= NextEntry
->Flink
;
2015 /* If we didn't find the driver, it doesn't need large pages */
2016 if (DriverFound
== FALSE
) return FALSE
;
2019 /* Nothing to do yet */
2020 DPRINT1("Large pages not supported!\n");
2026 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2027 IN ULONG SectionProtection
)
2029 ULONG Protection
= MM_ZERO_ACCESS
;
2031 /* Check if the caller gave anything */
2032 if (SectionProtection
)
2034 /* Always turn on execute access */
2035 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2037 /* Check if the registry setting is on or not */
2038 if (!MmEnforceWriteProtection
)
2040 /* Turn on write access too */
2041 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2045 /* Convert to internal PTE flags */
2046 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2047 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2049 /* Check for write access */
2050 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2052 /* Session space is not supported */
2055 DPRINT1("Session drivers not supported\n");
2056 ASSERT(SessionSpace
== FALSE
);
2060 /* Convert to internal PTE flag */
2061 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2065 /* If there's no access at all by now, convert to internal no access flag */
2066 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2068 /* Return the computed PTE protection */
2074 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2076 IN ULONG ProtectionMask
)
2078 /* I'm afraid to introduce regressions at the moment... */
2084 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2086 PIMAGE_NT_HEADERS NtHeaders
;
2087 PIMAGE_SECTION_HEADER Section
;
2088 PFN_NUMBER DriverPages
;
2089 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2090 ULONG Sections
, Size
;
2091 ULONG_PTR BaseAddress
, CurrentAddress
;
2092 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2093 ULONG CurrentMask
, CombinedMask
= 0;
2096 /* No need to write protect physical memory-backed drivers (large pages) */
2097 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2099 /* Get the image headers */
2100 NtHeaders
= RtlImageNtHeader(ImageBase
);
2101 if (!NtHeaders
) return;
2103 /* Check if this is a session driver or not */
2104 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2106 /* Don't touch NT4 drivers */
2107 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2108 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2113 DPRINT1("Session drivers not supported\n");
2117 /* These are the only protection masks we care about */
2118 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2120 /* Calculate the number of pages this driver is occupying */
2121 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
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 /* Loop all the sections */
2129 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2132 /* Get the section size */
2133 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2135 /* Get its virtual address */
2136 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2137 if (BaseAddress
< CurrentAddress
)
2139 /* Windows doesn't like these */
2140 DPRINT1("Badly linked image!\n");
2144 /* Remember the current address */
2145 CurrentAddress
= BaseAddress
+ Size
- 1;
2152 /* Get the number of sections and the first section header */
2153 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2154 ASSERT(Sections
!= 0);
2155 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2157 /* Set the address at the end to initialize the loop */
2158 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2159 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2161 /* Set the PTE points for the image, and loop its sections */
2162 StartPte
= MiAddressToPte(ImageBase
);
2163 LastPte
= StartPte
+ DriverPages
;
2166 /* Get the section size */
2167 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2169 /* Get its virtual address and PTE */
2170 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2171 PointerPte
= MiAddressToPte(BaseAddress
);
2173 /* Check if we were already protecting a run, and found a new run */
2174 if ((ComboPte
) && (PointerPte
> ComboPte
))
2176 /* Compute protection */
2177 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2180 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2182 /* Check for overlap */
2183 if (ComboPte
== StartPte
) StartPte
++;
2185 /* One done, reset variables */
2187 CombinedProtection
= 0;
2190 /* Break out when needed */
2191 if (PointerPte
>= LastPte
) break;
2193 /* Get the requested protection from the image header */
2194 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2195 if (SectionProtection
== CurrentProtection
)
2197 /* Same protection, so merge the request */
2198 CurrentAddress
= BaseAddress
+ Size
- 1;
2206 /* This is now a new section, so close up the old one */
2207 CurrentPte
= MiAddressToPte(CurrentAddress
);
2209 /* Check for overlap */
2210 if (CurrentPte
== PointerPte
)
2212 /* Skip the last PTE, since it overlaps with us */
2215 /* And set the PTE we will merge with */
2216 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2217 ComboPte
= PointerPte
;
2219 /* Get the most flexible protection by merging both */
2220 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2223 /* Loop any PTEs left */
2224 if (CurrentPte
>= StartPte
)
2227 ASSERT(StartPte
< LastPte
);
2229 /* Make sure we don't overflow past the last PTE in the driver */
2230 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2231 ASSERT(CurrentPte
>= StartPte
);
2233 /* Compute the protection and set it */
2234 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2235 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2239 StartPte
= PointerPte
;
2240 CurrentAddress
= BaseAddress
+ Size
- 1;
2241 CurrentProtection
= SectionProtection
;
2248 /* Is there a leftover section to merge? */
2251 /* Compute and set the protection */
2252 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2253 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2255 /* Handle overlap */
2256 if (ComboPte
== StartPte
) StartPte
++;
2259 /* Finally, handle the last section */
2260 CurrentPte
= MiAddressToPte(CurrentAddress
);
2261 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2263 /* Handle overlap */
2264 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2265 ASSERT(CurrentPte
>= StartPte
);
2267 /* Compute and set the protection */
2268 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2269 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2275 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2279 PETHREAD CurrentThread
= PsGetCurrentThread();
2280 PFN_COUNT PageCount
= 0;
2281 PFN_NUMBER PageFrameIndex
;
2285 /* Get the driver's base address */
2286 ImageBase
= MiPteToAddress(PointerPte
);
2287 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2289 /* If this is a large page, it's stuck in physical memory */
2290 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2292 /* Lock the working set */
2293 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2296 while (PointerPte
<= LastPte
)
2298 /* Check for valid PTE */
2299 if (PointerPte
->u
.Hard
.Valid
== 1)
2301 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2302 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2303 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2305 /* No working sets in ReactOS yet */
2309 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2313 /* Release the working set */
2314 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2316 /* Do we have any driver pages? */
2319 /* Update counters */
2320 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2326 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2328 ULONG_PTR ImageBase
;
2329 PIMAGE_NT_HEADERS NtHeaders
;
2330 ULONG Sections
, Alignment
, Size
;
2331 PIMAGE_SECTION_HEADER Section
;
2332 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2333 if (MmDisablePagingExecutive
) return;
2335 /* Get the driver base address and its NT header */
2336 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2337 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2338 if (!NtHeaders
) return;
2340 /* Get the sections and their alignment */
2341 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2342 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2344 /* Loop each section */
2345 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2348 /* Find PAGE or .edata */
2349 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2350 (*(PULONG
)Section
->Name
== 'ade.'))
2352 /* Had we already done some work? */
2355 /* Nope, setup the first PTE address */
2356 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2361 /* Compute the size */
2362 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2364 /* Find the last PTE that maps this section */
2365 LastPte
= MiAddressToPte(ImageBase
+
2366 Section
->VirtualAddress
+
2373 /* Had we found a section before? */
2376 /* Mark it as pageable */
2377 MiSetPagingOfDriver(PointerPte
, LastPte
);
2382 /* Keep searching */
2387 /* Handle the straggler */
2388 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2393 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2395 PIMAGE_NT_HEADERS NtHeader
;
2398 /* Get NT Headers */
2399 NtHeader
= RtlImageNtHeader(BaseAddress
);
2402 /* Check if this image is only safe for UP while we have 2+ CPUs */
2403 if ((KeNumberProcessors
> 1) &&
2404 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2411 /* Otherwise, it's safe */
2417 MmCheckSystemImage(IN HANDLE ImageHandle
,
2418 IN BOOLEAN PurgeSection
)
2421 HANDLE SectionHandle
;
2422 PVOID ViewBase
= NULL
;
2423 SIZE_T ViewSize
= 0;
2424 IO_STATUS_BLOCK IoStatusBlock
;
2425 FILE_STANDARD_INFORMATION FileStandardInfo
;
2426 KAPC_STATE ApcState
;
2427 PIMAGE_NT_HEADERS NtHeaders
;
2428 OBJECT_ATTRIBUTES ObjectAttributes
;
2431 /* Setup the object attributes */
2432 InitializeObjectAttributes(&ObjectAttributes
,
2434 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2438 /* Create a section for the DLL */
2439 Status
= ZwCreateSection(&SectionHandle
,
2440 SECTION_MAP_EXECUTE
,
2446 if (!NT_SUCCESS(Status
)) return Status
;
2448 /* Make sure we're in the system process */
2449 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2452 Status
= ZwMapViewOfSection(SectionHandle
,
2462 if (!NT_SUCCESS(Status
))
2464 /* We failed, close the handle and return */
2465 KeUnstackDetachProcess(&ApcState
);
2466 ZwClose(SectionHandle
);
2470 /* Now query image information */
2471 Status
= ZwQueryInformationFile(ImageHandle
,
2474 sizeof(FileStandardInfo
),
2475 FileStandardInformation
);
2476 if (NT_SUCCESS(Status
))
2478 /* First, verify the checksum */
2479 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2484 /* Set checksum failure */
2485 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2489 /* Make sure it's a real image */
2490 NtHeaders
= RtlImageNtHeader(ViewBase
);
2493 /* Set checksum failure */
2494 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2498 /* Make sure it's for the correct architecture */
2499 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2500 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2502 /* Set protection failure */
2503 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2507 /* Check that it's a valid SMP image if we have more then one CPU */
2508 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2510 /* Otherwise it's not the right image */
2511 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2515 /* Unmap the section, close the handle, and return status */
2517 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2518 KeUnstackDetachProcess(&ApcState
);
2519 ZwClose(SectionHandle
);
2525 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2526 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2527 IN PUNICODE_STRING LoadedName OPTIONAL
,
2529 OUT PVOID
*ModuleObject
,
2530 OUT PVOID
*ImageBaseAddress
)
2532 PVOID ModuleLoadBase
= NULL
;
2534 HANDLE FileHandle
= NULL
;
2535 OBJECT_ATTRIBUTES ObjectAttributes
;
2536 IO_STATUS_BLOCK IoStatusBlock
;
2537 PIMAGE_NT_HEADERS NtHeader
;
2538 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2539 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2540 ULONG EntrySize
, DriverSize
;
2541 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2542 PCHAR MissingApiName
, Buffer
;
2543 PWCHAR MissingDriverName
;
2544 HANDLE SectionHandle
;
2545 ACCESS_MASK DesiredAccess
;
2546 PVOID Section
= NULL
;
2547 BOOLEAN LockOwned
= FALSE
;
2548 PLIST_ENTRY NextEntry
;
2549 IMAGE_INFO ImageInfo
;
2553 /* Detect session-load */
2557 ASSERT(NamePrefix
== NULL
);
2558 ASSERT(LoadedName
== NULL
);
2560 /* Make sure the process is in session too */
2561 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2564 /* Allocate a buffer we'll use for names */
2565 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2566 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2568 /* Check for a separator */
2569 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2574 /* Loop the path until we get to the base name */
2575 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2576 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2578 /* Get the length */
2579 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2580 BaseLength
*= sizeof(WCHAR
);
2582 /* Setup the string */
2583 BaseName
.Length
= (USHORT
)BaseLength
;
2584 BaseName
.Buffer
= p
;
2588 /* Otherwise, we already have a base name */
2589 BaseName
.Length
= FileName
->Length
;
2590 BaseName
.Buffer
= FileName
->Buffer
;
2593 /* Setup the maximum length */
2594 BaseName
.MaximumLength
= BaseName
.Length
;
2596 /* Now compute the base directory */
2597 BaseDirectory
= *FileName
;
2598 BaseDirectory
.Length
-= BaseName
.Length
;
2599 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2601 /* And the prefix, which for now is just the name itself */
2602 PrefixName
= *FileName
;
2604 /* Check if we have a prefix */
2605 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2607 /* Check if we already have a name, use it instead */
2608 if (LoadedName
) BaseName
= *LoadedName
;
2610 /* Check for loader snap debugging */
2611 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2613 /* Print out standard string */
2614 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2615 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2618 /* Acquire the load lock */
2620 ASSERT(LockOwned
== FALSE
);
2622 KeEnterCriticalRegion();
2623 KeWaitForSingleObject(&MmSystemLoadLock
,
2629 /* Scan the module list */
2630 NextEntry
= PsLoadedModuleList
.Flink
;
2631 while (NextEntry
!= &PsLoadedModuleList
)
2633 /* Get the entry and compare the names */
2634 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2635 LDR_DATA_TABLE_ENTRY
,
2637 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2639 /* Found it, break out */
2644 NextEntry
= NextEntry
->Flink
;
2647 /* Check if we found the image */
2648 if (NextEntry
!= &PsLoadedModuleList
)
2650 /* Check if we had already mapped a section */
2653 /* Dereference and clear */
2654 ObDereferenceObject(Section
);
2658 /* Check if this was supposed to be a session load */
2661 /* It wasn't, so just return the data */
2662 *ModuleObject
= LdrEntry
;
2663 *ImageBaseAddress
= LdrEntry
->DllBase
;
2664 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2668 /* We don't support session loading yet */
2669 DPRINT1("Unsupported Session-Load!\n");
2678 /* It wasn't loaded, and we didn't have a previous attempt */
2679 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2680 KeLeaveCriticalRegion();
2683 /* Check if KD is enabled */
2684 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2686 /* FIXME: Attempt to get image from KD */
2689 /* We don't have a valid entry */
2692 /* Setup image attributes */
2693 InitializeObjectAttributes(&ObjectAttributes
,
2695 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2699 /* Open the image */
2700 Status
= ZwOpenFile(&FileHandle
,
2704 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2706 if (!NT_SUCCESS(Status
)) goto Quickie
;
2709 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2710 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2711 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2712 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2718 /* Check if this is a session-load */
2721 /* Then we only need read and execute */
2722 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2726 /* Otherwise, we can allow write access */
2727 DesiredAccess
= SECTION_ALL_ACCESS
;
2730 /* Initialize the attributes for the section */
2731 InitializeObjectAttributes(&ObjectAttributes
,
2733 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2737 /* Create the section */
2738 Status
= ZwCreateSection(&SectionHandle
,
2745 if (!NT_SUCCESS(Status
)) goto Quickie
;
2747 /* Now get the section pointer */
2748 Status
= ObReferenceObjectByHandle(SectionHandle
,
2749 SECTION_MAP_EXECUTE
,
2750 MmSectionObjectType
,
2754 ZwClose(SectionHandle
);
2755 if (!NT_SUCCESS(Status
)) goto Quickie
;
2757 /* Check if this was supposed to be a session-load */
2760 /* We don't support session loading yet */
2761 DPRINT1("Unsupported Session-Load!\n");
2765 /* Check the loader list again, we should end up in the path below */
2770 /* We don't have a valid entry */
2774 /* Load the image */
2775 Status
= MiLoadImageSection(&Section
,
2780 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
2782 /* Get the size of the driver */
2783 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
2785 /* Make sure we're not being loaded into session space */
2788 /* Check for success */
2789 if (NT_SUCCESS(Status
))
2791 /* Support large pages for drivers */
2792 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
2798 /* Dereference the section */
2799 ObDereferenceObject(Section
);
2803 /* Check for failure of the load earlier */
2804 if (!NT_SUCCESS(Status
)) goto Quickie
;
2806 /* Relocate the driver */
2807 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
2811 STATUS_CONFLICTING_ADDRESSES
,
2812 STATUS_INVALID_IMAGE_FORMAT
);
2813 if (!NT_SUCCESS(Status
)) goto Quickie
;
2816 /* Get the NT Header */
2817 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
2819 /* Calculate the size we'll need for the entry and allocate it */
2820 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2822 sizeof(UNICODE_NULL
);
2824 /* Allocate the entry */
2825 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2829 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2833 /* Setup the entry */
2834 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
2835 LdrEntry
->LoadCount
= 1;
2836 LdrEntry
->LoadedImports
= LoadedImports
;
2837 LdrEntry
->PatchInformation
= NULL
;
2839 /* Check the version */
2840 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
2841 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
2843 /* Mark this image as a native image */
2844 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
2847 /* Setup the rest of the entry */
2848 LdrEntry
->DllBase
= ModuleLoadBase
;
2849 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
2850 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
2851 LdrEntry
->SizeOfImage
= DriverSize
;
2852 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
2853 LdrEntry
->SectionPointer
= Section
;
2855 /* Now write the DLL name */
2856 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
2857 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
2858 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
2860 /* Copy and null-terminate it */
2861 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
2864 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2866 /* Now allocate the full name */
2867 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2869 sizeof(UNICODE_NULL
),
2871 if (!LdrEntry
->FullDllName
.Buffer
)
2873 /* Don't fail, just set it to zero */
2874 LdrEntry
->FullDllName
.Length
= 0;
2875 LdrEntry
->FullDllName
.MaximumLength
= 0;
2880 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
2881 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
2883 /* Copy and null-terminate */
2884 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
2887 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2891 MiProcessLoaderEntry(LdrEntry
, TRUE
);
2893 /* Resolve imports */
2894 MissingApiName
= Buffer
;
2895 Status
= MiResolveImageReferences(ModuleLoadBase
,
2901 if (!NT_SUCCESS(Status
))
2904 MiProcessLoaderEntry(LdrEntry
, FALSE
);
2906 /* Check if we need to free the name */
2907 if (LdrEntry
->FullDllName
.Buffer
)
2910 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
2913 /* Free the entry itself */
2914 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
2919 /* Update the loader entry */
2920 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
2921 LDRP_ENTRY_PROCESSED
|
2923 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2924 LdrEntry
->LoadedImports
= LoadedImports
;
2926 /* FIXME: Call driver verifier's loader function */
2928 /* Write-protect the system image */
2929 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
2931 /* Check if notifications are enabled */
2932 if (PsImageNotifyEnabled
)
2934 /* Fill out the notification data */
2935 ImageInfo
.Properties
= 0;
2936 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
2937 ImageInfo
.SystemModeImage
= TRUE
;
2938 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
2939 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
2940 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
2942 /* Send the notification */
2943 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
2946 #if defined(KDBG) || defined(_WINKD_)
2947 /* MiCacheImageSymbols doesn't detect rossym */
2950 /* Check if there's symbols */
2951 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
2954 /* Check if the system root is present */
2955 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
2956 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
2958 /* Add the system root */
2959 UnicodeTemp
= PrefixName
;
2960 UnicodeTemp
.Buffer
+= 11;
2961 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
2964 &SharedUserData
->NtSystemRoot
[2],
2969 /* Build the name */
2970 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2973 /* Setup the ansi string */
2974 RtlInitString(&AnsiTemp
, Buffer
);
2976 /* Notify the debugger */
2977 DbgLoadImageSymbols(&AnsiTemp
,
2979 (ULONG_PTR
)ZwCurrentProcess());
2980 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
2983 /* Page the driver */
2984 ASSERT(Section
== NULL
);
2985 MiEnablePagingOfDriver(LdrEntry
);
2987 /* Return pointers */
2988 *ModuleObject
= LdrEntry
;
2989 *ImageBaseAddress
= LdrEntry
->DllBase
;
2992 /* Check if we have the lock acquired */
2995 /* Release the lock */
2996 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2997 KeLeaveCriticalRegion();
3001 /* If we have a file handle, close it */
3002 if (FileHandle
) ZwClose(FileHandle
);
3004 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3005 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3007 /* Free the name buffer and return status */
3008 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3012 PLDR_DATA_TABLE_ENTRY
3014 MiLookupDataTableEntry(IN PVOID Address
)
3016 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3017 PLIST_ENTRY NextEntry
;
3021 NextEntry
= PsLoadedModuleList
.Flink
;
3024 /* Get the loader entry */
3025 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3026 LDR_DATA_TABLE_ENTRY
,
3029 /* Check if the address matches */
3030 if ((Address
>= LdrEntry
->DllBase
) &&
3031 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3032 LdrEntry
->SizeOfImage
)))
3035 FoundEntry
= LdrEntry
;
3040 NextEntry
= NextEntry
->Flink
;
3041 } while(NextEntry
!= &PsLoadedModuleList
);
3043 /* Return the entry */
3047 /* PUBLIC FUNCTIONS ***********************************************************/
3054 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3056 PMMPTE StartPte
, EndPte
;
3057 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3060 /* Get the loader entry */
3061 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3062 if (!LdrEntry
) return NULL
;
3064 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3065 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3067 /* Don't do anything, just return the base address */
3068 return LdrEntry
->DllBase
;
3071 /* Wait for active DPCs to finish before we page out the driver */
3072 KeFlushQueuedDpcs();
3074 /* Get the PTE range for the whole driver image */
3075 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3076 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3078 /* Enable paging for the PTE range */
3079 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3080 MiSetPagingOfDriver(StartPte
, EndPte
);
3082 /* Return the base address */
3083 return LdrEntry
->DllBase
;
3091 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3101 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3103 PVOID ProcAddress
= NULL
;
3104 ANSI_STRING AnsiRoutineName
;
3106 PLIST_ENTRY NextEntry
;
3107 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3108 BOOLEAN Found
= FALSE
;
3109 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3110 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3113 /* Convert routine to ansi name */
3114 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3117 if (!NT_SUCCESS(Status
)) return NULL
;
3120 KeEnterCriticalRegion();
3121 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3123 /* Loop the loaded module list */
3124 NextEntry
= PsLoadedModuleList
.Flink
;
3125 while (NextEntry
!= &PsLoadedModuleList
)
3128 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3129 LDR_DATA_TABLE_ENTRY
,
3132 /* Check if it's the kernel or HAL */
3133 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3139 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3146 /* Check if we found a valid binary */
3149 /* Find the procedure name */
3150 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3153 /* Break out if we found it or if we already tried both modules */
3154 if (ProcAddress
) break;
3155 if (Modules
== 2) break;
3159 NextEntry
= NextEntry
->Flink
;
3162 /* Release the lock */
3163 ExReleaseResourceLite(&PsLoadedModuleResource
);
3164 KeLeaveCriticalRegion();
3166 /* Free the string and return */
3167 RtlFreeAnsiString(&AnsiRoutineName
);