2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * ReactOS Portable Systems Group
10 /* INCLUDES *******************************************************************/
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 /* GCC's incompetence strikes again */
22 sprintf_nt(IN PCHAR Buffer
,
28 vsprintf(Buffer
, Format
, ap
);
32 /* GLOBALS ********************************************************************/
34 LIST_ENTRY PsLoadedModuleList
;
35 LIST_ENTRY MmLoadedUserImageList
;
36 KSPIN_LOCK PsLoadedModuleSpinLock
;
37 ERESOURCE PsLoadedModuleResource
;
38 ULONG_PTR PsNtosImageBase
;
39 KMUTANT MmSystemLoadLock
;
41 PFN_NUMBER MmTotalSystemDriverPages
;
43 PVOID MmUnloadedDrivers
;
44 PVOID MmLastUnloadedDrivers
;
46 BOOLEAN MmMakeLowMemory
;
47 BOOLEAN MmEnforceWriteProtection
= TRUE
;
49 PMMPTE MiKernelResourceStartPte
, MiKernelResourceEndPte
;
50 ULONG_PTR ExPoolCodeStart
, ExPoolCodeEnd
, MmPoolCodeStart
, MmPoolCodeEnd
;
51 ULONG_PTR MmPteCodeStart
, MmPteCodeEnd
;
53 /* FUNCTIONS ******************************************************************/
57 MiCacheImageSymbols(IN PVOID BaseAddress
)
60 PVOID DebugDirectory
= NULL
;
63 /* Make sure it's safe to access the image */
66 /* Get the debug directory */
67 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
69 IMAGE_DIRECTORY_ENTRY_DEBUG
,
72 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
78 /* Return the directory */
79 return DebugDirectory
;
84 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
86 IN PUNICODE_STRING FileName
,
87 IN BOOLEAN SessionLoad
,
88 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
90 PROS_SECTION_OBJECT Section
= *SectionPtr
;
96 LARGE_INTEGER SectionOffset
= {{0, 0}};
97 BOOLEAN LoadSymbols
= FALSE
;
99 PMMPTE PointerPte
, LastPte
;
104 /* Detect session load */
108 DPRINT1("Session loading not yet supported!\n");
112 /* Not session load, shouldn't have an entry */
113 ASSERT(LdrEntry
== NULL
);
115 /* Attach to the system process */
116 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
118 /* Check if we need to load symbols */
119 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
123 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
127 Process
= PsGetCurrentProcess();
128 Status
= MmMapViewOfSection(Section
,
139 /* Re-enable the flag */
140 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
142 /* Check if we failed with distinguished status code */
143 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
145 /* Change it to something more generic */
146 Status
= STATUS_INVALID_IMAGE_FORMAT
;
149 /* Now check if we failed */
150 if (!NT_SUCCESS(Status
))
152 /* Detach and return */
153 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status
);
154 KeUnstackDetachProcess(&ApcState
);
158 /* Reserve system PTEs needed */
159 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
160 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
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
;
169 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName
, DriverBase
, PteCount
);
171 /* Loop the new driver PTEs */
172 TempPte
= ValidKernelPte
;
173 while (PointerPte
< LastPte
)
175 /* Allocate a page */
176 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
180 if (FileName
->Buffer
)
182 pos
= wcsrchr(FileName
->Buffer
, '\\');
183 len
= wcslen(pos
) * sizeof(WCHAR
);
184 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
187 TempPte
.u
.Hard
.PageFrameNumber
= MiAllocatePfn(PointerPte
, MM_EXECUTE
);
190 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
197 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
199 /* Now unmap the view */
200 Status
= MmUnmapViewOfSection(Process
, Base
);
201 ASSERT(NT_SUCCESS(Status
));
203 /* Detach and return status */
204 KeUnstackDetachProcess(&ApcState
);
210 MiLocateExportName(IN PVOID DllBase
,
214 PUSHORT OrdinalTable
;
215 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
216 LONG Low
= 0, Mid
= 0, High
, Ret
;
223 /* Get the export directory */
224 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
226 IMAGE_DIRECTORY_ENTRY_EXPORT
,
228 if (!ExportDirectory
) return NULL
;
230 /* Setup name tables */
231 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
232 ExportDirectory
->AddressOfNames
);
233 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
234 ExportDirectory
->AddressOfNameOrdinals
);
236 /* Do a binary search */
237 High
= ExportDirectory
->NumberOfNames
- 1;
240 /* Get new middle value */
241 Mid
= (Low
+ High
) >> 1;
244 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
262 /* Check if we couldn't find it */
263 if (High
< Low
) return NULL
;
265 /* Otherwise, this is the ordinal */
266 Ordinal
= OrdinalTable
[Mid
];
268 /* Resolve the address and write it */
269 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
270 ExportDirectory
->AddressOfFunctions
);
271 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
273 /* Check if the function is actually a forwarder */
274 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
275 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
287 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
288 IN PLIST_ENTRY ListHead
)
290 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
291 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
292 PMM_DLL_INITIALIZE DllInit
;
293 UNICODE_STRING RegPath
, ImportName
;
296 /* Try to see if the image exports a DllInitialize routine */
297 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
299 if (!DllInit
) return STATUS_SUCCESS
;
301 /* Do a temporary copy of BaseDllName called ImportName
302 * because we'll alter the length of the string
304 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
305 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
306 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
308 /* Obtain the path to this dll's service in the registry */
309 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
310 ImportName
.Length
+ sizeof(UNICODE_NULL
);
311 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
312 RegPath
.MaximumLength
,
315 /* Check if this allocation was unsuccessful */
316 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
318 /* Build and append the service name itself */
319 RegPath
.Length
= ServicesKeyName
.Length
;
320 RtlCopyMemory(RegPath
.Buffer
,
321 ServicesKeyName
.Buffer
,
322 ServicesKeyName
.Length
);
324 /* Check if there is a dot in the filename */
325 if (wcschr(ImportName
.Buffer
, L
'.'))
327 /* Remove the extension */
328 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
329 ImportName
.Buffer
) * sizeof(WCHAR
);
332 /* Append service name (the basename without extension) */
333 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
335 /* Now call the DllInit func */
336 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
337 Status
= DllInit(&RegPath
);
340 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
342 /* Return status value which DllInitialize returned */
348 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
354 /* Get the unload routine */
355 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
356 if (!Func
) return FALSE
;
358 /* Call it and check for success */
360 if (!NT_SUCCESS(Status
)) return FALSE
;
362 /* Lie about the load count so we can unload the image */
363 ASSERT(LdrEntry
->LoadCount
== 0);
364 LdrEntry
->LoadCount
= 1;
366 /* Unload it and return true */
367 MmUnloadSystemImage(LdrEntry
);
373 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
376 LOAD_IMPORTS SingleEntry
;
377 PLDR_DATA_TABLE_ENTRY LdrEntry
;
378 PVOID CurrentImports
;
381 /* Check if there's no imports or if we're a boot driver */
382 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
383 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
384 (ImportList
->Count
== 0))
386 /* Then there's nothing to do */
387 return STATUS_SUCCESS
;
390 /* Check for single-entry */
391 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
394 SingleEntry
.Count
= 1;
395 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
397 /* Use this as the import list */
398 ImportList
= &SingleEntry
;
401 /* Loop the import list */
402 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
405 LdrEntry
= ImportList
->Entry
[i
];
406 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
408 /* Skip boot loaded images */
409 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
411 /* Dereference the entry */
412 ASSERT(LdrEntry
->LoadCount
>= 1);
413 if (!--LdrEntry
->LoadCount
)
415 /* Save the import data in case unload fails */
416 CurrentImports
= LdrEntry
->LoadedImports
;
418 /* This is the last entry */
419 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
420 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
422 /* Unloading worked, parse this DLL's imports too */
423 MiDereferenceImports(CurrentImports
);
425 /* Check if we had valid imports */
426 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
427 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
428 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
431 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
436 /* Unload failed, restore imports */
437 LdrEntry
->LoadedImports
= CurrentImports
;
443 return STATUS_SUCCESS
;
448 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
452 /* Check if there's no imports or we're a boot driver or only one entry */
453 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
454 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
455 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
461 /* Otherwise, free the import list */
462 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
463 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
468 MiFindExportedRoutineByName(IN PVOID DllBase
,
469 IN PANSI_STRING ExportName
)
472 PUSHORT OrdinalTable
;
473 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
474 LONG Low
= 0, Mid
= 0, High
, Ret
;
481 /* Get the export directory */
482 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
484 IMAGE_DIRECTORY_ENTRY_EXPORT
,
486 if (!ExportDirectory
) return NULL
;
488 /* Setup name tables */
489 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
490 ExportDirectory
->AddressOfNames
);
491 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
492 ExportDirectory
->AddressOfNameOrdinals
);
494 /* Do a binary search */
495 High
= ExportDirectory
->NumberOfNames
- 1;
498 /* Get new middle value */
499 Mid
= (Low
+ High
) >> 1;
502 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
520 /* Check if we couldn't find it */
521 if (High
< Low
) return NULL
;
523 /* Otherwise, this is the ordinal */
524 Ordinal
= OrdinalTable
[Mid
];
526 /* Validate the ordinal */
527 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
529 /* Resolve the address and write it */
530 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
531 ExportDirectory
->AddressOfFunctions
);
532 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
535 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
536 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
542 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
547 /* Acquire module list lock */
548 KeEnterCriticalRegion();
549 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
551 /* Acquire the spinlock too as we will insert or remove the entry */
552 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
554 /* Insert or remove from the list */
555 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
556 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
559 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
560 ExReleaseResourceLite(&PsLoadedModuleResource
);
561 KeLeaveCriticalRegion();
567 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
572 ULONG_PTR OldBaseTop
, Delta
;
573 PLDR_DATA_TABLE_ENTRY LdrEntry
;
574 PLIST_ENTRY NextEntry
;
577 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
578 // since a real version of Windows would fail at this point, but they seem
579 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
580 // a feature which isn't even used by Windows. Priorities, priorities...
581 // Please note that Microsoft WDK EULA and license prohibits using
582 // the information contained within it for the generation of "non-Windows"
583 // drivers, which is precisely what LD will generate, since an LD driver
584 // will not load on Windows.
586 #ifdef _WORKING_LINKER_
589 PULONG_PTR ImageThunk
;
590 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
592 /* Calculate the top and delta */
593 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
594 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
596 /* Loop the loader block */
597 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
598 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
599 NextEntry
= NextEntry
->Flink
)
601 /* Get the loader entry */
602 LdrEntry
= CONTAINING_RECORD(NextEntry
,
603 LDR_DATA_TABLE_ENTRY
,
605 #ifdef _WORKING_LINKER_
607 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
609 IMAGE_DIRECTORY_ENTRY_IAT
,
611 if (!ImageThunk
) continue;
613 /* Make sure we have an IAT */
614 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
615 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
617 /* Check if it's within this module */
618 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
621 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
622 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
623 *ImageThunk
+= Delta
;
627 /* Get the import table */
628 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
630 IMAGE_DIRECTORY_ENTRY_IMPORT
,
632 if (!ImportDescriptor
) continue;
634 /* Make sure we have an IAT */
635 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
636 while ((ImportDescriptor
->Name
) &&
637 (ImportDescriptor
->OriginalFirstThunk
))
639 /* Get the image thunk */
640 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
641 ImportDescriptor
->FirstThunk
);
644 /* Check if it's within this module */
645 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
648 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
649 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
650 *ImageThunk
+= Delta
;
653 /* Go to the next thunk */
657 /* Go to the next import */
666 MiSnapThunk(IN PVOID DllBase
,
668 IN PIMAGE_THUNK_DATA Name
,
669 IN PIMAGE_THUNK_DATA Address
,
670 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
672 IN BOOLEAN SnapForwarder
,
673 OUT PCHAR
*MissingApi
)
678 PUSHORT OrdinalTable
;
679 PIMAGE_IMPORT_BY_NAME NameImport
;
681 ULONG Low
= 0, Mid
= 0, High
;
684 PCHAR MissingForwarder
;
685 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
688 UNICODE_STRING ForwarderName
;
689 PLIST_ENTRY NextEntry
;
690 PLDR_DATA_TABLE_ENTRY LdrEntry
;
691 ULONG ForwardExportSize
;
692 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
693 PIMAGE_IMPORT_BY_NAME ForwardName
;
694 SIZE_T ForwardLength
;
695 IMAGE_THUNK_DATA ForwardThunk
;
698 /* Check if this is an ordinal */
699 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
700 if ((IsOrdinal
) && !(SnapForwarder
))
702 /* Get the ordinal number and set it as missing */
703 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
704 ExportDirectory
->Base
);
705 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
709 /* Get the VA if we don't have to snap */
710 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
711 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
713 /* Copy the procedure name */
714 RtlStringCbCopyA(*MissingApi
,
715 MAXIMUM_FILENAME_LENGTH
,
716 (PCHAR
)&NameImport
->Name
[0]);
718 /* Setup name tables */
719 DPRINT("Import name: %s\n", NameImport
->Name
);
720 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
721 ExportDirectory
->AddressOfNames
);
722 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
723 ExportDirectory
->AddressOfNameOrdinals
);
725 /* Get the hint and check if it's valid */
726 Hint
= NameImport
->Hint
;
727 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
728 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
730 /* We have a match, get the ordinal number from here */
731 Ordinal
= OrdinalTable
[Hint
];
735 /* Do a binary search */
736 High
= ExportDirectory
->NumberOfNames
- 1;
739 /* Get new middle value */
740 Mid
= (Low
+ High
) >> 1;
743 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
761 /* Check if we couldn't find it */
764 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
765 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
768 /* Otherwise, this is the ordinal */
769 Ordinal
= OrdinalTable
[Mid
];
773 /* Check if the ordinal is invalid */
774 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
777 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
781 /* In case the forwarder is missing */
782 MissingForwarder
= NameBuffer
;
784 /* Resolve the address and write it */
785 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
786 ExportDirectory
->AddressOfFunctions
);
787 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
789 /* Assume success from now on */
790 Status
= STATUS_SUCCESS
;
792 /* Check if the function is actually a forwarder */
793 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
794 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
796 /* Now assume failure in case the forwarder doesn't exist */
797 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
799 /* Build the forwarder name */
800 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
801 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
804 DllName
.MaximumLength
= DllName
.Length
;
807 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
811 /* We failed, just return an error */
815 /* Loop the module list */
816 NextEntry
= PsLoadedModuleList
.Flink
;
817 while (NextEntry
!= &PsLoadedModuleList
)
819 /* Get the loader entry */
820 LdrEntry
= CONTAINING_RECORD(NextEntry
,
821 LDR_DATA_TABLE_ENTRY
,
824 /* Check if it matches */
825 if (RtlPrefixString((PSTRING
)&ForwarderName
,
826 (PSTRING
)&LdrEntry
->BaseDllName
,
829 /* Get the forwarder export directory */
830 ForwardExportDirectory
=
831 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
833 IMAGE_DIRECTORY_ENTRY_EXPORT
,
835 if (!ForwardExportDirectory
) break;
837 /* Allocate a name entry */
838 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
840 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
841 sizeof(*ForwardName
) +
844 if (!ForwardName
) break;
847 RtlCopyMemory(&ForwardName
->Name
[0],
848 DllName
.Buffer
+ DllName
.Length
,
850 ForwardName
->Hint
= 0;
852 /* Set the new address */
853 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
855 /* Snap the forwarder */
856 Status
= MiSnapThunk(LdrEntry
->DllBase
,
860 ForwardExportDirectory
,
865 /* Free the forwarder name and set the thunk */
866 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
867 Address
->u1
= ForwardThunk
.u1
;
871 /* Go to the next entry */
872 NextEntry
= NextEntry
->Flink
;
876 RtlFreeUnicodeString(&ForwarderName
);
886 MmUnloadSystemImage(IN PVOID ImageHandle
)
888 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
889 PVOID BaseAddress
= LdrEntry
->DllBase
;
892 BOOLEAN HadEntry
= FALSE
;
894 /* Acquire the loader lock */
895 KeEnterCriticalRegion();
896 KeWaitForSingleObject(&MmSystemLoadLock
,
902 /* Check if this driver was loaded at boot and didn't get imports parsed */
903 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
905 /* We should still be alive */
906 ASSERT(LdrEntry
->LoadCount
!= 0);
907 LdrEntry
->LoadCount
--;
909 /* Check if we're still loaded */
910 if (LdrEntry
->LoadCount
) goto Done
;
912 /* We should cleanup... are symbols loaded */
913 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
915 /* Create the ANSI name */
916 Status
= RtlUnicodeStringToAnsiString(&TempName
,
917 &LdrEntry
->BaseDllName
,
919 if (NT_SUCCESS(Status
))
921 /* Unload the symbols */
922 DbgUnLoadImageSymbols(&TempName
,
924 (ULONG_PTR
)ZwCurrentProcess());
925 RtlFreeAnsiString(&TempName
);
929 /* FIXME: Free the driver */
930 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
931 //MmFreeSection(LdrEntry->DllBase);
933 /* Check if we're linked in */
934 if (LdrEntry
->InLoadOrderLinks
.Flink
)
937 MiProcessLoaderEntry(LdrEntry
, FALSE
);
941 /* Dereference and clear the imports */
942 MiDereferenceImports(LdrEntry
->LoadedImports
);
943 MiClearImports(LdrEntry
);
945 /* Check if the entry needs to go away */
948 /* Check if it had a name */
949 if (LdrEntry
->FullDllName
.Buffer
)
952 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
955 /* Check if we had a section */
956 if (LdrEntry
->SectionPointer
)
959 ObDereferenceObject(LdrEntry
->SectionPointer
);
963 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
966 /* Release the system lock and return */
968 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
969 KeLeaveCriticalRegion();
970 return STATUS_SUCCESS
;
975 MiResolveImageReferences(IN PVOID ImageBase
,
976 IN PUNICODE_STRING ImageFileDirectory
,
977 IN PUNICODE_STRING NamePrefix OPTIONAL
,
978 OUT PCHAR
*MissingApi
,
979 OUT PWCHAR
*MissingDriver
,
980 OUT PLOAD_IMPORTS
*LoadImports
)
982 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
983 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
984 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
985 PLOAD_IMPORTS LoadedImports
, NewImports
;
986 ULONG GdiLink
, NormalLink
, i
;
987 BOOLEAN ReferenceNeeded
, Loaded
;
988 ANSI_STRING TempString
;
989 UNICODE_STRING NameString
, DllName
;
990 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
991 PVOID ImportBase
, DllBase
;
992 PLIST_ENTRY NextEntry
;
993 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
995 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
997 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
998 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1000 /* Assume no imports */
1001 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1003 /* Get the import descriptor */
1004 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1006 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1008 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1010 /* Loop all imports to count them */
1011 for (CurrentImport
= ImportDescriptor
;
1012 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1019 /* Make sure we have non-zero imports */
1022 /* Calculate and allocate the list we'll need */
1023 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1024 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1030 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1031 LoadedImports
->Count
= ImportCount
;
1037 LoadedImports
= NULL
;
1040 /* Reset the import count and loop descriptors again */
1041 ImportCount
= GdiLink
= NormalLink
= 0;
1042 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1045 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1047 /* Check if this is a GDI driver */
1049 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1051 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1052 NormalLink
= NormalLink
|
1053 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1054 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1055 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1056 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1058 /* Check if this is a valid GDI driver */
1059 if ((GdiLink
) && (NormalLink
))
1061 /* It's not, it's importing stuff it shouldn't be! */
1062 MiDereferenceImports(LoadedImports
);
1063 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1064 return STATUS_PROCEDURE_NOT_FOUND
;
1067 /* Check for user-mode printer or video card drivers, which don't belong */
1068 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1069 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1070 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1071 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1072 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1073 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1075 /* This is not kernel code */
1076 MiDereferenceImports(LoadedImports
);
1077 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1078 return STATUS_PROCEDURE_NOT_FOUND
;
1081 /* Check if this is a "core" import, which doesn't get referenced */
1082 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1083 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1084 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1086 /* Don't reference this */
1087 ReferenceNeeded
= FALSE
;
1091 /* Reference these modules */
1092 ReferenceNeeded
= TRUE
;
1095 /* Now setup a unicode string for the import */
1096 RtlInitAnsiString(&TempString
, ImportName
);
1097 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1098 if (!NT_SUCCESS(Status
))
1101 MiDereferenceImports(LoadedImports
);
1102 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1106 /* We don't support name prefixes yet */
1107 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1109 /* Remember that we haven't loaded the import at this point */
1114 /* Loop the driver list */
1115 NextEntry
= PsLoadedModuleList
.Flink
;
1116 while (NextEntry
!= &PsLoadedModuleList
)
1118 /* Get the loader entry and compare the name */
1119 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1120 LDR_DATA_TABLE_ENTRY
,
1122 if (RtlEqualUnicodeString(&NameString
,
1123 &LdrEntry
->BaseDllName
,
1126 /* Get the base address */
1127 ImportBase
= LdrEntry
->DllBase
;
1129 /* Check if we haven't loaded yet, and we need references */
1130 if (!(Loaded
) && (ReferenceNeeded
))
1132 /* Make sure we're not already loading */
1133 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1135 /* Increase the load count */
1136 LdrEntry
->LoadCount
++;
1140 /* Done, break out */
1144 /* Go to the next entry */
1145 NextEntry
= NextEntry
->Flink
;
1148 /* Check if we haven't loaded the import yet */
1151 /* Setup the import DLL name */
1152 DllName
.MaximumLength
= NameString
.Length
+
1153 ImageFileDirectory
->Length
+
1154 sizeof(UNICODE_NULL
);
1155 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1156 DllName
.MaximumLength
,
1160 /* Setup the base length and copy it */
1161 DllName
.Length
= ImageFileDirectory
->Length
;
1162 RtlCopyMemory(DllName
.Buffer
,
1163 ImageFileDirectory
->Buffer
,
1164 ImageFileDirectory
->Length
);
1166 /* Now add the import name and null-terminate it */
1167 RtlAppendUnicodeStringToString(&DllName
,
1169 DllName
.Buffer
[DllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1171 /* Load the image */
1172 Status
= MmLoadSystemImage(&DllName
,
1178 if (NT_SUCCESS(Status
))
1180 /* We can free the DLL Name */
1181 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1185 /* Fill out the information for the error */
1186 *MissingDriver
= DllName
.Buffer
;
1187 *(PULONG
)MissingDriver
|= 1;
1190 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1195 /* We're out of resources */
1196 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1199 /* Check if we're OK until now */
1200 if (NT_SUCCESS(Status
))
1202 /* We're now loaded */
1206 ASSERT(DllBase
= DllEntry
->DllBase
);
1208 /* Call the initialization routines */
1209 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1210 if (!NT_SUCCESS(Status
))
1212 /* We failed, unload the image */
1213 MmUnloadSystemImage(DllEntry
);
1214 DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status
);
1220 /* Check if we failed by here */
1221 if (!NT_SUCCESS(Status
))
1223 /* Cleanup and return */
1224 RtlFreeUnicodeString(&NameString
);
1225 MiDereferenceImports(LoadedImports
);
1226 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1230 /* Loop again to make sure that everything is OK */
1234 /* Check if we're support to reference this import */
1235 if ((ReferenceNeeded
) && (LoadedImports
))
1237 /* Make sure we're not already loading */
1238 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1241 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1246 /* Free the import name */
1247 RtlFreeUnicodeString(&NameString
);
1249 /* Set the missing driver name and get the export directory */
1250 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1251 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1253 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1255 if (!ExportDirectory
)
1257 /* Cleanup and return */
1258 MiDereferenceImports(LoadedImports
);
1259 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1260 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1261 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1264 /* Make sure we have an IAT */
1265 if (ImportDescriptor
->OriginalFirstThunk
)
1267 /* Get the first thunks */
1268 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1269 ImportDescriptor
->OriginalFirstThunk
);
1270 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1271 ImportDescriptor
->FirstThunk
);
1274 while (OrigThunk
->u1
.AddressOfData
)
1277 Status
= MiSnapThunk(ImportBase
,
1285 if (!NT_SUCCESS(Status
))
1287 /* Cleanup and return */
1288 MiDereferenceImports(LoadedImports
);
1289 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1293 /* Reset the buffer */
1294 *MissingApi
= MissingApiBuffer
;
1298 /* Go to the next import */
1302 /* Check if we have an import list */
1305 /* Reset the count again, and loop entries */
1307 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1309 if (LoadedImports
->Entry
[i
])
1311 /* Got an entry, OR it with 1 in case it's the single entry */
1312 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1313 MM_SYSLDR_SINGLE_ENTRY
);
1318 /* Check if we had no imports */
1321 /* Free the list and set it to no imports */
1322 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1323 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1325 else if (ImportCount
== 1)
1327 /* Just one entry, we can free the table and only use our entry */
1328 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1329 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1331 else if (ImportCount
!= LoadedImports
->Count
)
1333 /* Allocate a new list */
1334 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1335 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1341 NewImports
->Count
= 0;
1343 /* Loop all the imports */
1344 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1346 /* Make sure it's valid */
1347 if (LoadedImports
->Entry
[i
])
1350 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1351 NewImports
->Count
++;
1355 /* Free the old copy */
1356 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1357 LoadedImports
= NewImports
;
1361 /* Return the list */
1362 *LoadImports
= LoadedImports
;
1365 /* Return success */
1366 return STATUS_SUCCESS
;
1372 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1374 PLIST_ENTRY NextEntry
;
1376 PIMAGE_NT_HEADERS NtHeader
;
1377 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1378 PIMAGE_FILE_HEADER FileHeader
;
1379 BOOLEAN ValidRelocs
;
1380 PIMAGE_DATA_DIRECTORY DataDirectory
;
1381 PVOID DllBase
, NewImageAddress
;
1383 PMMPTE PointerPte
, StartPte
, LastPte
;
1386 MMPTE TempPte
, OldPte
;
1388 /* Loop driver list */
1389 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1390 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1391 NextEntry
= NextEntry
->Flink
)
1393 /* Get the loader entry and NT header */
1394 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1395 LDR_DATA_TABLE_ENTRY
,
1397 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1400 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1402 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1403 &LdrEntry
->FullDllName
);
1405 /* Get the first PTE and the number of PTEs we'll need */
1406 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1407 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1408 LastPte
= StartPte
+ PteCount
;
1412 while (PointerPte
< LastPte
)
1415 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1416 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1417 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1418 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1422 /* Skip kernel and HAL */
1423 /* ROS HACK: Skip BOOTVID/KDCOM too */
1425 if (i
<= 4) continue;
1427 /* Skip non-drivers */
1428 if (!NtHeader
) continue;
1430 /* Get the file header and make sure we can relocate */
1431 FileHeader
= &NtHeader
->FileHeader
;
1432 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1433 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1434 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1436 /* Everything made sense until now, check the relocation section too */
1437 DataDirectory
= &NtHeader
->OptionalHeader
.
1438 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1439 if (!DataDirectory
->VirtualAddress
)
1441 /* We don't really have relocations */
1442 ValidRelocs
= FALSE
;
1446 /* Make sure the size is valid */
1447 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1448 LdrEntry
->SizeOfImage
)
1450 /* They're not, skip */
1454 /* We have relocations */
1458 /* Remember the original address */
1459 DllBase
= LdrEntry
->DllBase
;
1462 PointerPte
= StartPte
;
1463 while (PointerPte
< LastPte
)
1465 /* Mark the page modified in the PFN database */
1466 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1467 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1468 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1469 Pfn1
->u3
.e1
.Modified
= TRUE
;
1475 /* Now reserve system PTEs for the image */
1476 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1479 /* Shouldn't happen */
1480 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1484 /* This is the new virtual address for the module */
1485 LastPte
= PointerPte
+ PteCount
;
1486 NewImageAddress
= MiPteToAddress(PointerPte
);
1489 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1490 ASSERT(ExpInitializationPhase
== 0);
1492 /* Loop the new driver PTEs */
1493 TempPte
= ValidKernelPte
;
1494 while (PointerPte
< LastPte
)
1496 /* Copy the old data */
1498 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1500 /* Set page number from the loader's memory */
1501 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1504 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1511 /* Update position */
1512 PointerPte
-= PteCount
;
1515 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1517 /* Set the image base to the address where the loader put it */
1518 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1520 /* Check if we had relocations */
1523 /* Relocate the image */
1524 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1528 STATUS_CONFLICTING_ADDRESSES
,
1529 STATUS_INVALID_IMAGE_FORMAT
);
1530 if (!NT_SUCCESS(Status
))
1532 /* This shouldn't happen */
1533 DPRINT1("Relocations failed!\n");
1538 /* Update the loader entry */
1539 LdrEntry
->DllBase
= NewImageAddress
;
1541 /* Update the thunks */
1542 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1543 MiUpdateThunks(LoaderBlock
,
1546 LdrEntry
->SizeOfImage
);
1548 /* Update the loader entry */
1549 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1550 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1551 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1552 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1554 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1561 MiBuildImportsForBootDrivers(VOID
)
1563 PLIST_ENTRY NextEntry
, NextEntry2
;
1564 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1565 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1566 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1567 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1568 PLOAD_IMPORTS LoadedImports
;
1569 ULONG LoadedImportsSize
, ImportSize
;
1570 PULONG_PTR ImageThunk
;
1571 ULONG_PTR DllBase
, DllEnd
;
1572 ULONG Modules
= 0, i
, j
= 0;
1573 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1575 /* Initialize variables */
1576 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1578 /* Loop the loaded module list... we are early enough that no lock is needed */
1579 NextEntry
= PsLoadedModuleList
.Flink
;
1580 while (NextEntry
!= &PsLoadedModuleList
)
1583 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1584 LDR_DATA_TABLE_ENTRY
,
1587 /* Check if it's the kernel or HAL */
1588 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1591 KernelEntry
= LdrEntry
;
1593 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1596 HalEntry
= LdrEntry
;
1599 /* Check if this is a driver DLL */
1600 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1602 /* Check if this is the HAL or kernel */
1603 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1605 /* Add a reference */
1606 LdrEntry
->LoadCount
= 1;
1610 /* No referencing needed */
1611 LdrEntry
->LoadCount
= 0;
1616 /* No referencing needed */
1617 LdrEntry
->LoadCount
= 0;
1620 /* Remember this came from the loader */
1621 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1624 NextEntry
= NextEntry
->Flink
;
1628 /* We must have at least found the kernel and HAL */
1629 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1631 /* Allocate the list */
1632 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1633 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1635 /* Loop the loaded module list again */
1636 NextEntry
= PsLoadedModuleList
.Flink
;
1637 while (NextEntry
!= &PsLoadedModuleList
)
1640 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1641 LDR_DATA_TABLE_ENTRY
,
1643 #ifdef _WORKING_LOADER_
1644 /* Get its imports */
1645 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1647 IMAGE_DIRECTORY_ENTRY_IAT
,
1651 /* Get its imports */
1652 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1654 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1656 if (!ImportDescriptor
)
1660 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1661 NextEntry
= NextEntry
->Flink
;
1665 /* Clear the list and count the number of IAT thunks */
1666 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1667 #ifdef _WORKING_LOADER_
1668 ImportSize
/= sizeof(ULONG_PTR
);
1670 /* Scan the thunks */
1671 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1673 DllBase
= DllEnd
= i
= 0;
1674 while ((ImportDescriptor
->Name
) &&
1675 (ImportDescriptor
->OriginalFirstThunk
))
1677 /* Get the image thunk */
1678 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1679 ImportDescriptor
->FirstThunk
);
1683 /* Do we already have an address? */
1686 /* Is the thunk in the same address? */
1687 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1689 /* Skip it, we already have a reference for it */
1690 ASSERT(EntryArray
[j
]);
1696 /* Loop the loaded module list to locate this address owner */
1698 NextEntry2
= PsLoadedModuleList
.Flink
;
1699 while (NextEntry2
!= &PsLoadedModuleList
)
1702 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1703 LDR_DATA_TABLE_ENTRY
,
1706 /* Get the address range for this module */
1707 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1708 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1710 /* Check if this IAT entry matches it */
1711 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1714 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1715 EntryArray
[j
] = LdrEntry2
;
1719 /* Keep searching */
1720 NextEntry2
= NextEntry2
->Flink
;
1724 /* Do we have a thunk outside the range? */
1725 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1730 /* Should not be happening */
1731 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1732 LdrEntry
, ImageThunk
, *ImageThunk
);
1736 /* Reset if we hit this */
1739 #ifndef _WORKING_LOADER_
1748 /* Now scan how many imports we really have */
1749 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1751 /* Skip HAL and kernel */
1752 if ((EntryArray
[i
]) &&
1753 (EntryArray
[i
] != HalEntry
) &&
1754 (EntryArray
[i
] != KernelEntry
))
1756 /* A valid reference */
1757 LastEntry
= EntryArray
[i
];
1762 /* Do we have any imports after all? */
1766 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1768 else if (ImportSize
== 1)
1770 /* A single entry import */
1771 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
1772 LastEntry
->LoadCount
++;
1776 /* We need an import table */
1777 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
1778 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1781 ASSERT(LoadedImports
);
1783 /* Save the count */
1784 LoadedImports
->Count
= ImportSize
;
1786 /* Now copy all imports */
1787 for (i
= 0, j
= 0; i
< Modules
; i
++)
1789 /* Skip HAL and kernel */
1790 if ((EntryArray
[i
]) &&
1791 (EntryArray
[i
] != HalEntry
) &&
1792 (EntryArray
[i
] != KernelEntry
))
1794 /* A valid reference */
1795 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
1796 LoadedImports
->Entry
[j
] = EntryArray
[i
];
1797 EntryArray
[i
]->LoadCount
++;
1802 /* Should had as many entries as we expected */
1803 ASSERT(j
== ImportSize
);
1804 LdrEntry
->LoadedImports
= LoadedImports
;
1808 NextEntry
= NextEntry
->Flink
;
1811 /* Free the initial array */
1812 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
1814 /* FIXME: Might not need to keep the HAL/Kernel imports around */
1816 /* Kernel and HAL are loaded at boot */
1817 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1818 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1820 /* All worked well */
1821 return STATUS_SUCCESS
;
1827 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1830 PIMAGE_NT_HEADERS NtHeaders
;
1831 PIMAGE_SECTION_HEADER SectionHeader
;
1832 ULONG Sections
, Size
;
1834 /* Get the kernel section header */
1835 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1836 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
1837 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
1839 /* Loop all the sections */
1840 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1843 /* Grab the size of the section */
1844 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
1846 /* Check for .RSRC section */
1847 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
1849 /* Remember the PTEs so we can modify them later */
1850 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
1851 SectionHeader
->VirtualAddress
);
1852 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
1853 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
1855 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
1857 /* POOLCODE vs. POOLMI */
1858 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
1860 /* Found Ex* Pool code */
1861 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1862 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1864 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
1866 /* Found Mm* Pool code */
1867 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1868 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
1871 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
1872 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
1874 /* Found MISYSPTE (Mm System PTE code)*/
1875 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
1876 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
1888 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1890 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1891 PLIST_ENTRY ListHead
, NextEntry
;
1894 /* Setup the loaded module list and locks */
1895 ExInitializeResourceLite(&PsLoadedModuleResource
);
1896 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1897 InitializeListHead(&PsLoadedModuleList
);
1899 /* Get loop variables and the kernel entry */
1900 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1901 NextEntry
= ListHead
->Flink
;
1902 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1903 LDR_DATA_TABLE_ENTRY
,
1905 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1907 /* Locate resource section, pool code, and system pte code */
1908 MiLocateKernelSections(LdrEntry
);
1910 /* Loop the loader block */
1911 while (NextEntry
!= ListHead
)
1913 /* Get the loader entry */
1914 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1915 LDR_DATA_TABLE_ENTRY
,
1918 /* FIXME: ROS HACK. Make sure this is a driver */
1919 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1921 /* Skip this entry */
1922 NextEntry
= NextEntry
->Flink
;
1926 /* Calculate the size we'll need and allocate a copy */
1927 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1928 LdrEntry
->BaseDllName
.MaximumLength
+
1929 sizeof(UNICODE_NULL
);
1930 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1931 if (!NewEntry
) return FALSE
;
1933 /* Copy the entry over */
1934 *NewEntry
= *LdrEntry
;
1936 /* Allocate the name */
1937 NewEntry
->FullDllName
.Buffer
=
1938 ExAllocatePoolWithTag(PagedPool
,
1939 LdrEntry
->FullDllName
.MaximumLength
+
1940 sizeof(UNICODE_NULL
),
1942 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1944 /* Set the base name */
1945 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1947 /* Copy the full and base name */
1948 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1949 LdrEntry
->FullDllName
.Buffer
,
1950 LdrEntry
->FullDllName
.MaximumLength
);
1951 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1952 LdrEntry
->BaseDllName
.Buffer
,
1953 LdrEntry
->BaseDllName
.MaximumLength
);
1955 /* Null-terminate the base name */
1956 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1957 sizeof(WCHAR
)] = UNICODE_NULL
;
1959 /* Insert the entry into the list */
1960 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1961 NextEntry
= NextEntry
->Flink
;
1964 /* Build the import lists for the boot drivers */
1965 MiBuildImportsForBootDrivers();
1973 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
1974 IN OUT PVOID
*ImageBaseAddress
,
1975 IN PUNICODE_STRING BaseImageName
,
1976 IN BOOLEAN BootDriver
)
1978 PLIST_ENTRY NextEntry
;
1979 BOOLEAN DriverFound
= FALSE
;
1980 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
1981 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
1982 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
1985 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
1986 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
1989 /* Make sure there's enough system PTEs for a large page driver */
1990 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
1995 /* This happens if the registry key had a "*" (wildcard) in it */
1996 if (MiLargePageAllDrivers
== 0)
1998 /* It didn't, so scan the list */
1999 NextEntry
= MiLargePageDriverList
.Flink
;
2000 while (NextEntry
!= &MiLargePageDriverList
)
2002 /* Check if the driver name matches */
2003 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2004 MI_LARGE_PAGE_DRIVER_ENTRY
,
2006 if (RtlEqualUnicodeString(BaseImageName
,
2007 &LargePageDriverEntry
->BaseName
,
2010 /* Enable large pages for this driver */
2016 NextEntry
= NextEntry
->Flink
;
2019 /* If we didn't find the driver, it doesn't need large pages */
2020 if (DriverFound
== FALSE
) return FALSE
;
2023 /* Nothing to do yet */
2024 DPRINT1("Large pages not supported!\n");
2030 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2031 IN ULONG SectionProtection
)
2033 ULONG Protection
= MM_ZERO_ACCESS
;
2035 /* Check if the caller gave anything */
2036 if (SectionProtection
)
2038 /* Always turn on execute access */
2039 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2041 /* Check if the registry setting is on or not */
2042 if (!MmEnforceWriteProtection
)
2044 /* Turn on write access too */
2045 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2049 /* Convert to internal PTE flags */
2050 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2051 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2053 /* Check for write access */
2054 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2056 /* Session space is not supported */
2059 DPRINT1("Session drivers not supported\n");
2060 ASSERT(SessionSpace
== FALSE
);
2064 /* Convert to internal PTE flag */
2065 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2069 /* If there's no access at all by now, convert to internal no access flag */
2070 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2072 /* Return the computed PTE protection */
2078 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2080 IN ULONG ProtectionMask
)
2082 /* I'm afraid to introduce regressions at the moment... */
2088 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2090 PIMAGE_NT_HEADERS NtHeaders
;
2091 PIMAGE_SECTION_HEADER Section
;
2092 PFN_NUMBER DriverPages
;
2093 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2094 ULONG Sections
, Size
;
2095 ULONG_PTR BaseAddress
, CurrentAddress
;
2096 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2097 ULONG CurrentMask
, CombinedMask
= 0;
2100 /* No need to write protect physical memory-backed drivers (large pages) */
2101 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2103 /* Get the image headers */
2104 NtHeaders
= RtlImageNtHeader(ImageBase
);
2105 if (!NtHeaders
) return;
2107 /* Check if this is a session driver or not */
2108 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2110 /* Don't touch NT4 drivers */
2111 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2112 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2117 DPRINT1("Session drivers not supported\n");
2121 /* These are the only protection masks we care about */
2122 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2124 /* Calculate the number of pages this driver is occupying */
2125 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2127 /* Get the number of sections and the first section header */
2128 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2129 ASSERT(Sections
!= 0);
2130 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2132 /* Loop all the sections */
2133 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2136 /* Get the section size */
2137 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2139 /* Get its virtual address */
2140 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2141 if (BaseAddress
< CurrentAddress
)
2143 /* Windows doesn't like these */
2144 DPRINT1("Badly linked image!\n");
2148 /* Remember the current address */
2149 CurrentAddress
= BaseAddress
+ Size
- 1;
2156 /* Get the number of sections and the first section header */
2157 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2158 ASSERT(Sections
!= 0);
2159 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2161 /* Set the address at the end to initialize the loop */
2162 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2163 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2165 /* Set the PTE points for the image, and loop its sections */
2166 StartPte
= MiAddressToPte(ImageBase
);
2167 LastPte
= StartPte
+ DriverPages
;
2170 /* Get the section size */
2171 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2173 /* Get its virtual address and PTE */
2174 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2175 PointerPte
= MiAddressToPte(BaseAddress
);
2177 /* Check if we were already protecting a run, and found a new run */
2178 if ((ComboPte
) && (PointerPte
> ComboPte
))
2180 /* Compute protection */
2181 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2184 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2186 /* Check for overlap */
2187 if (ComboPte
== StartPte
) StartPte
++;
2189 /* One done, reset variables */
2191 CombinedProtection
= 0;
2194 /* Break out when needed */
2195 if (PointerPte
>= LastPte
) break;
2197 /* Get the requested protection from the image header */
2198 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2199 if (SectionProtection
== CurrentProtection
)
2201 /* Same protection, so merge the request */
2202 CurrentAddress
= BaseAddress
+ Size
- 1;
2210 /* This is now a new section, so close up the old one */
2211 CurrentPte
= MiAddressToPte(CurrentAddress
);
2213 /* Check for overlap */
2214 if (CurrentPte
== PointerPte
)
2216 /* Skip the last PTE, since it overlaps with us */
2219 /* And set the PTE we will merge with */
2220 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2221 ComboPte
= PointerPte
;
2223 /* Get the most flexible protection by merging both */
2224 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2227 /* Loop any PTEs left */
2228 if (CurrentPte
>= StartPte
)
2231 ASSERT(StartPte
< LastPte
);
2233 /* Make sure we don't overflow past the last PTE in the driver */
2234 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2235 ASSERT(CurrentPte
>= StartPte
);
2237 /* Compute the protection and set it */
2238 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2239 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2243 StartPte
= PointerPte
;
2244 CurrentAddress
= BaseAddress
+ Size
- 1;
2245 CurrentProtection
= SectionProtection
;
2252 /* Is there a leftover section to merge? */
2255 /* Compute and set the protection */
2256 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2257 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2259 /* Handle overlap */
2260 if (ComboPte
== StartPte
) StartPte
++;
2263 /* Finally, handle the last section */
2264 CurrentPte
= MiAddressToPte(CurrentAddress
);
2265 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2267 /* Handle overlap */
2268 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2269 ASSERT(CurrentPte
>= StartPte
);
2271 /* Compute and set the protection */
2272 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2273 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2279 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2283 PETHREAD CurrentThread
= PsGetCurrentThread();
2284 PFN_COUNT PageCount
= 0;
2285 PFN_NUMBER PageFrameIndex
;
2289 /* Get the driver's base address */
2290 ImageBase
= MiPteToAddress(PointerPte
);
2291 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2293 /* If this is a large page, it's stuck in physical memory */
2294 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2296 /* Lock the working set */
2297 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2300 while (PointerPte
<= LastPte
)
2302 /* Check for valid PTE */
2303 if (PointerPte
->u
.Hard
.Valid
== 1)
2305 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2306 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2307 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2309 /* No working sets in ReactOS yet */
2313 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2317 /* Release the working set */
2318 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2320 /* Do we have any driver pages? */
2323 /* Update counters */
2324 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2330 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2332 ULONG_PTR ImageBase
;
2333 PIMAGE_NT_HEADERS NtHeaders
;
2334 ULONG Sections
, Alignment
, Size
;
2335 PIMAGE_SECTION_HEADER Section
;
2336 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2337 if (MmDisablePagingExecutive
) return;
2339 /* Get the driver base address and its NT header */
2340 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2341 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2342 if (!NtHeaders
) return;
2344 /* Get the sections and their alignment */
2345 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2346 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2348 /* Loop each section */
2349 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2352 /* Find PAGE or .edata */
2353 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2354 (*(PULONG
)Section
->Name
== 'ade.'))
2356 /* Had we already done some work? */
2359 /* Nope, setup the first PTE address */
2360 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2365 /* Compute the size */
2366 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2368 /* Find the last PTE that maps this section */
2369 LastPte
= MiAddressToPte(ImageBase
+
2370 Section
->VirtualAddress
+
2377 /* Had we found a section before? */
2380 /* Mark it as pageable */
2381 MiSetPagingOfDriver(PointerPte
, LastPte
);
2386 /* Keep searching */
2391 /* Handle the straggler */
2392 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2397 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2399 PIMAGE_NT_HEADERS NtHeader
;
2402 /* Get NT Headers */
2403 NtHeader
= RtlImageNtHeader(BaseAddress
);
2406 /* Check if this image is only safe for UP while we have 2+ CPUs */
2407 if ((KeNumberProcessors
> 1) &&
2408 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2415 /* Otherwise, it's safe */
2421 MmCheckSystemImage(IN HANDLE ImageHandle
,
2422 IN BOOLEAN PurgeSection
)
2425 HANDLE SectionHandle
;
2426 PVOID ViewBase
= NULL
;
2427 SIZE_T ViewSize
= 0;
2428 IO_STATUS_BLOCK IoStatusBlock
;
2429 FILE_STANDARD_INFORMATION FileStandardInfo
;
2430 KAPC_STATE ApcState
;
2431 PIMAGE_NT_HEADERS NtHeaders
;
2432 OBJECT_ATTRIBUTES ObjectAttributes
;
2435 /* Setup the object attributes */
2436 InitializeObjectAttributes(&ObjectAttributes
,
2438 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2442 /* Create a section for the DLL */
2443 Status
= ZwCreateSection(&SectionHandle
,
2444 SECTION_MAP_EXECUTE
,
2450 if (!NT_SUCCESS(Status
))
2452 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2456 /* Make sure we're in the system process */
2457 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2460 Status
= ZwMapViewOfSection(SectionHandle
,
2470 if (!NT_SUCCESS(Status
))
2472 /* We failed, close the handle and return */
2473 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2474 KeUnstackDetachProcess(&ApcState
);
2475 ZwClose(SectionHandle
);
2479 /* Now query image information */
2480 Status
= ZwQueryInformationFile(ImageHandle
,
2483 sizeof(FileStandardInfo
),
2484 FileStandardInformation
);
2485 if (NT_SUCCESS(Status
))
2487 /* First, verify the checksum */
2488 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2493 /* Set checksum failure */
2494 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2498 /* Make sure it's a real image */
2499 NtHeaders
= RtlImageNtHeader(ViewBase
);
2502 /* Set checksum failure */
2503 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2507 /* Make sure it's for the correct architecture */
2508 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2509 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2511 /* Set protection failure */
2512 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2516 /* Check that it's a valid SMP image if we have more then one CPU */
2517 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2519 /* Otherwise it's not the right image */
2520 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2524 /* Unmap the section, close the handle, and return status */
2526 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2527 KeUnstackDetachProcess(&ApcState
);
2528 ZwClose(SectionHandle
);
2534 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2535 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2536 IN PUNICODE_STRING LoadedName OPTIONAL
,
2538 OUT PVOID
*ModuleObject
,
2539 OUT PVOID
*ImageBaseAddress
)
2541 PVOID ModuleLoadBase
= NULL
;
2543 HANDLE FileHandle
= NULL
;
2544 OBJECT_ATTRIBUTES ObjectAttributes
;
2545 IO_STATUS_BLOCK IoStatusBlock
;
2546 PIMAGE_NT_HEADERS NtHeader
;
2547 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2548 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2549 ULONG EntrySize
, DriverSize
;
2550 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2551 PCHAR MissingApiName
, Buffer
;
2552 PWCHAR MissingDriverName
;
2553 HANDLE SectionHandle
;
2554 ACCESS_MASK DesiredAccess
;
2555 PVOID Section
= NULL
;
2556 BOOLEAN LockOwned
= FALSE
;
2557 PLIST_ENTRY NextEntry
;
2558 IMAGE_INFO ImageInfo
;
2562 /* Detect session-load */
2566 ASSERT(NamePrefix
== NULL
);
2567 ASSERT(LoadedName
== NULL
);
2569 /* Make sure the process is in session too */
2570 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2573 /* Allocate a buffer we'll use for names */
2574 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2575 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2577 /* Check for a separator */
2578 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2583 /* Loop the path until we get to the base name */
2584 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2585 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2587 /* Get the length */
2588 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2589 BaseLength
*= sizeof(WCHAR
);
2591 /* Setup the string */
2592 BaseName
.Length
= (USHORT
)BaseLength
;
2593 BaseName
.Buffer
= p
;
2597 /* Otherwise, we already have a base name */
2598 BaseName
.Length
= FileName
->Length
;
2599 BaseName
.Buffer
= FileName
->Buffer
;
2602 /* Setup the maximum length */
2603 BaseName
.MaximumLength
= BaseName
.Length
;
2605 /* Now compute the base directory */
2606 BaseDirectory
= *FileName
;
2607 BaseDirectory
.Length
-= BaseName
.Length
;
2608 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2610 /* And the prefix, which for now is just the name itself */
2611 PrefixName
= *FileName
;
2613 /* Check if we have a prefix */
2614 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2616 /* Check if we already have a name, use it instead */
2617 if (LoadedName
) BaseName
= *LoadedName
;
2619 /* Check for loader snap debugging */
2620 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2622 /* Print out standard string */
2623 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2624 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2627 /* Acquire the load lock */
2629 ASSERT(LockOwned
== FALSE
);
2631 KeEnterCriticalRegion();
2632 KeWaitForSingleObject(&MmSystemLoadLock
,
2638 /* Scan the module list */
2639 NextEntry
= PsLoadedModuleList
.Flink
;
2640 while (NextEntry
!= &PsLoadedModuleList
)
2642 /* Get the entry and compare the names */
2643 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2644 LDR_DATA_TABLE_ENTRY
,
2646 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2648 /* Found it, break out */
2653 NextEntry
= NextEntry
->Flink
;
2656 /* Check if we found the image */
2657 if (NextEntry
!= &PsLoadedModuleList
)
2659 /* Check if we had already mapped a section */
2662 /* Dereference and clear */
2663 ObDereferenceObject(Section
);
2667 /* Check if this was supposed to be a session load */
2670 /* It wasn't, so just return the data */
2671 *ModuleObject
= LdrEntry
;
2672 *ImageBaseAddress
= LdrEntry
->DllBase
;
2673 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2677 /* We don't support session loading yet */
2678 DPRINT1("Unsupported Session-Load!\n");
2687 /* It wasn't loaded, and we didn't have a previous attempt */
2688 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2689 KeLeaveCriticalRegion();
2692 /* Check if KD is enabled */
2693 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2695 /* FIXME: Attempt to get image from KD */
2698 /* We don't have a valid entry */
2701 /* Setup image attributes */
2702 InitializeObjectAttributes(&ObjectAttributes
,
2704 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2708 /* Open the image */
2709 Status
= ZwOpenFile(&FileHandle
,
2713 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2715 if (!NT_SUCCESS(Status
))
2717 DPRINT1("ZwOpenFile failed with status 0x%x\n", Status
);
2722 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2723 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2724 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2725 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2731 /* Check if this is a session-load */
2734 /* Then we only need read and execute */
2735 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2739 /* Otherwise, we can allow write access */
2740 DesiredAccess
= SECTION_ALL_ACCESS
;
2743 /* Initialize the attributes for the section */
2744 InitializeObjectAttributes(&ObjectAttributes
,
2746 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2750 /* Create the section */
2751 Status
= ZwCreateSection(&SectionHandle
,
2758 if (!NT_SUCCESS(Status
))
2760 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2764 /* Now get the section pointer */
2765 Status
= ObReferenceObjectByHandle(SectionHandle
,
2766 SECTION_MAP_EXECUTE
,
2767 MmSectionObjectType
,
2771 ZwClose(SectionHandle
);
2772 if (!NT_SUCCESS(Status
)) goto Quickie
;
2774 /* Check if this was supposed to be a session-load */
2777 /* We don't support session loading yet */
2778 DPRINT1("Unsupported Session-Load!\n");
2782 /* Check the loader list again, we should end up in the path below */
2787 /* We don't have a valid entry */
2791 /* Load the image */
2792 Status
= MiLoadImageSection(&Section
,
2797 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
2799 /* Get the size of the driver */
2800 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
2802 /* Make sure we're not being loaded into session space */
2805 /* Check for success */
2806 if (NT_SUCCESS(Status
))
2808 /* Support large pages for drivers */
2809 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
2815 /* Dereference the section */
2816 ObDereferenceObject(Section
);
2820 /* Check for failure of the load earlier */
2821 if (!NT_SUCCESS(Status
))
2823 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
2827 /* Relocate the driver */
2828 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
2832 STATUS_CONFLICTING_ADDRESSES
,
2833 STATUS_INVALID_IMAGE_FORMAT
);
2834 if (!NT_SUCCESS(Status
))
2836 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
2840 /* Get the NT Header */
2841 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
2843 /* Calculate the size we'll need for the entry and allocate it */
2844 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2846 sizeof(UNICODE_NULL
);
2848 /* Allocate the entry */
2849 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2853 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2857 /* Setup the entry */
2858 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
2859 LdrEntry
->LoadCount
= 1;
2860 LdrEntry
->LoadedImports
= LoadedImports
;
2861 LdrEntry
->PatchInformation
= NULL
;
2863 /* Check the version */
2864 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
2865 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
2867 /* Mark this image as a native image */
2868 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
2871 /* Setup the rest of the entry */
2872 LdrEntry
->DllBase
= ModuleLoadBase
;
2873 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
2874 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
2875 LdrEntry
->SizeOfImage
= DriverSize
;
2876 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
2877 LdrEntry
->SectionPointer
= Section
;
2879 /* Now write the DLL name */
2880 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
2881 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
2882 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
2884 /* Copy and null-terminate it */
2885 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
2888 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2890 /* Now allocate the full name */
2891 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2893 sizeof(UNICODE_NULL
),
2895 if (!LdrEntry
->FullDllName
.Buffer
)
2897 /* Don't fail, just set it to zero */
2898 LdrEntry
->FullDllName
.Length
= 0;
2899 LdrEntry
->FullDllName
.MaximumLength
= 0;
2904 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
2905 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
2907 /* Copy and null-terminate */
2908 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
2911 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2915 MiProcessLoaderEntry(LdrEntry
, TRUE
);
2917 /* Resolve imports */
2918 MissingApiName
= Buffer
;
2919 Status
= MiResolveImageReferences(ModuleLoadBase
,
2925 if (!NT_SUCCESS(Status
))
2927 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
2930 MiProcessLoaderEntry(LdrEntry
, FALSE
);
2932 /* Check if we need to free the name */
2933 if (LdrEntry
->FullDllName
.Buffer
)
2936 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
2939 /* Free the entry itself */
2940 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
2945 /* Update the loader entry */
2946 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
2947 LDRP_ENTRY_PROCESSED
|
2949 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2950 LdrEntry
->LoadedImports
= LoadedImports
;
2952 /* FIXME: Call driver verifier's loader function */
2954 /* Write-protect the system image */
2955 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
2957 /* Check if notifications are enabled */
2958 if (PsImageNotifyEnabled
)
2960 /* Fill out the notification data */
2961 ImageInfo
.Properties
= 0;
2962 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
2963 ImageInfo
.SystemModeImage
= TRUE
;
2964 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
2965 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
2966 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
2968 /* Send the notification */
2969 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
2972 #if defined(KDBG) || defined(_WINKD_)
2973 /* MiCacheImageSymbols doesn't detect rossym */
2976 /* Check if there's symbols */
2977 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
2980 /* Check if the system root is present */
2981 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
2982 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
2984 /* Add the system root */
2985 UnicodeTemp
= PrefixName
;
2986 UnicodeTemp
.Buffer
+= 11;
2987 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
2990 &SharedUserData
->NtSystemRoot
[2],
2995 /* Build the name */
2996 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2999 /* Setup the ansi string */
3000 RtlInitString(&AnsiTemp
, Buffer
);
3002 /* Notify the debugger */
3003 DbgLoadImageSymbols(&AnsiTemp
,
3005 (ULONG_PTR
)ZwCurrentProcess());
3006 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3009 /* Page the driver */
3010 ASSERT(Section
== NULL
);
3011 MiEnablePagingOfDriver(LdrEntry
);
3013 /* Return pointers */
3014 *ModuleObject
= LdrEntry
;
3015 *ImageBaseAddress
= LdrEntry
->DllBase
;
3018 /* Check if we have the lock acquired */
3021 /* Release the lock */
3022 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3023 KeLeaveCriticalRegion();
3027 /* If we have a file handle, close it */
3028 if (FileHandle
) ZwClose(FileHandle
);
3030 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3031 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3033 /* Free the name buffer and return status */
3034 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3038 PLDR_DATA_TABLE_ENTRY
3040 MiLookupDataTableEntry(IN PVOID Address
)
3042 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3043 PLIST_ENTRY NextEntry
;
3047 NextEntry
= PsLoadedModuleList
.Flink
;
3050 /* Get the loader entry */
3051 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3052 LDR_DATA_TABLE_ENTRY
,
3055 /* Check if the address matches */
3056 if ((Address
>= LdrEntry
->DllBase
) &&
3057 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3058 LdrEntry
->SizeOfImage
)))
3061 FoundEntry
= LdrEntry
;
3066 NextEntry
= NextEntry
->Flink
;
3067 } while(NextEntry
!= &PsLoadedModuleList
);
3069 /* Return the entry */
3073 /* PUBLIC FUNCTIONS ***********************************************************/
3080 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3082 PMMPTE StartPte
, EndPte
;
3083 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3086 /* Get the loader entry */
3087 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3088 if (!LdrEntry
) return NULL
;
3090 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3091 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3093 /* Don't do anything, just return the base address */
3094 return LdrEntry
->DllBase
;
3097 /* Wait for active DPCs to finish before we page out the driver */
3098 KeFlushQueuedDpcs();
3100 /* Get the PTE range for the whole driver image */
3101 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3102 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3104 /* Enable paging for the PTE range */
3105 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3106 MiSetPagingOfDriver(StartPte
, EndPte
);
3108 /* Return the base address */
3109 return LdrEntry
->DllBase
;
3117 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3127 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3129 PVOID ProcAddress
= NULL
;
3130 ANSI_STRING AnsiRoutineName
;
3132 PLIST_ENTRY NextEntry
;
3133 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3134 BOOLEAN Found
= FALSE
;
3135 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3136 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3139 /* Convert routine to ansi name */
3140 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3143 if (!NT_SUCCESS(Status
)) return NULL
;
3146 KeEnterCriticalRegion();
3147 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3149 /* Loop the loaded module list */
3150 NextEntry
= PsLoadedModuleList
.Flink
;
3151 while (NextEntry
!= &PsLoadedModuleList
)
3154 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3155 LDR_DATA_TABLE_ENTRY
,
3158 /* Check if it's the kernel or HAL */
3159 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3165 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3172 /* Check if we found a valid binary */
3175 /* Find the procedure name */
3176 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3179 /* Break out if we found it or if we already tried both modules */
3180 if (ProcAddress
) break;
3181 if (Modules
== 2) break;
3185 NextEntry
= NextEntry
->Flink
;
3188 /* Release the lock */
3189 ExReleaseResourceLite(&PsLoadedModuleResource
);
3190 KeLeaveCriticalRegion();
3192 /* Free the string and return */
3193 RtlFreeAnsiString(&AnsiRoutineName
);