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");
109 ASSERT(FALSE
); // while (TRUE);
110 return STATUS_NOT_IMPLEMENTED
;
113 /* Not session load, shouldn't have an entry */
114 ASSERT(LdrEntry
== NULL
);
116 /* Attach to the system process */
117 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
119 /* Check if we need to load symbols */
120 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
124 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
128 Process
= PsGetCurrentProcess();
129 Status
= MmMapViewOfSection(Section
,
140 /* Re-enable the flag */
141 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
143 /* Check if we failed with distinguished status code */
144 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
146 /* Change it to something more generic */
147 Status
= STATUS_INVALID_IMAGE_FORMAT
;
150 /* Now check if we failed */
151 if (!NT_SUCCESS(Status
))
153 /* Detach and return */
154 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status
);
155 KeUnstackDetachProcess(&ApcState
);
159 /* Reserve system PTEs needed */
160 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
161 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
164 DPRINT1("MiReserveSystemPtes failed\n");
165 KeUnstackDetachProcess(&ApcState
);
166 return STATUS_INSUFFICIENT_RESOURCES
;
169 /* New driver base */
170 LastPte
= PointerPte
+ PteCount
;
171 DriverBase
= MiPteToAddress(PointerPte
);
173 /* The driver is here */
174 *ImageBase
= DriverBase
;
175 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName
, DriverBase
, PteCount
);
177 /* Loop the new driver PTEs */
178 TempPte
= ValidKernelPte
;
179 while (PointerPte
< LastPte
)
181 /* Allocate a page */
182 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
186 if (FileName
->Buffer
)
188 pos
= wcsrchr(FileName
->Buffer
, '\\');
189 len
= wcslen(pos
) * sizeof(WCHAR
);
190 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
193 TempPte
.u
.Hard
.PageFrameNumber
= MiAllocatePfn(PointerPte
, MM_EXECUTE
);
196 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
203 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
205 /* Now unmap the view */
206 Status
= MmUnmapViewOfSection(Process
, Base
);
207 ASSERT(NT_SUCCESS(Status
));
209 /* Detach and return status */
210 KeUnstackDetachProcess(&ApcState
);
216 MiLocateExportName(IN PVOID DllBase
,
220 PUSHORT OrdinalTable
;
221 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
222 LONG Low
= 0, Mid
= 0, High
, Ret
;
229 /* Get the export directory */
230 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
232 IMAGE_DIRECTORY_ENTRY_EXPORT
,
234 if (!ExportDirectory
) return NULL
;
236 /* Setup name tables */
237 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
238 ExportDirectory
->AddressOfNames
);
239 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
240 ExportDirectory
->AddressOfNameOrdinals
);
242 /* Do a binary search */
243 High
= ExportDirectory
->NumberOfNames
- 1;
246 /* Get new middle value */
247 Mid
= (Low
+ High
) >> 1;
250 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
268 /* Check if we couldn't find it */
269 if (High
< Low
) return NULL
;
271 /* Otherwise, this is the ordinal */
272 Ordinal
= OrdinalTable
[Mid
];
274 /* Resolve the address and write it */
275 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
276 ExportDirectory
->AddressOfFunctions
);
277 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
279 /* Check if the function is actually a forwarder */
280 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
281 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
293 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
294 IN PLIST_ENTRY ListHead
)
296 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
297 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
298 PMM_DLL_INITIALIZE DllInit
;
299 UNICODE_STRING RegPath
, ImportName
;
302 /* Try to see if the image exports a DllInitialize routine */
303 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
305 if (!DllInit
) return STATUS_SUCCESS
;
307 /* Do a temporary copy of BaseDllName called ImportName
308 * because we'll alter the length of the string
310 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
311 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
312 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
314 /* Obtain the path to this dll's service in the registry */
315 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
316 ImportName
.Length
+ sizeof(UNICODE_NULL
);
317 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
318 RegPath
.MaximumLength
,
321 /* Check if this allocation was unsuccessful */
322 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
324 /* Build and append the service name itself */
325 RegPath
.Length
= ServicesKeyName
.Length
;
326 RtlCopyMemory(RegPath
.Buffer
,
327 ServicesKeyName
.Buffer
,
328 ServicesKeyName
.Length
);
330 /* Check if there is a dot in the filename */
331 if (wcschr(ImportName
.Buffer
, L
'.'))
333 /* Remove the extension */
334 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
335 ImportName
.Buffer
) * sizeof(WCHAR
);
338 /* Append service name (the basename without extension) */
339 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
341 /* Now call the DllInit func */
342 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
343 Status
= DllInit(&RegPath
);
346 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
348 /* Return status value which DllInitialize returned */
354 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
360 /* Get the unload routine */
361 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
362 if (!Func
) return FALSE
;
364 /* Call it and check for success */
366 if (!NT_SUCCESS(Status
)) return FALSE
;
368 /* Lie about the load count so we can unload the image */
369 ASSERT(LdrEntry
->LoadCount
== 0);
370 LdrEntry
->LoadCount
= 1;
372 /* Unload it and return true */
373 MmUnloadSystemImage(LdrEntry
);
379 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
382 LOAD_IMPORTS SingleEntry
;
383 PLDR_DATA_TABLE_ENTRY LdrEntry
;
384 PVOID CurrentImports
;
387 /* Check if there's no imports or if we're a boot driver */
388 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
389 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
390 (ImportList
->Count
== 0))
392 /* Then there's nothing to do */
393 return STATUS_SUCCESS
;
396 /* Check for single-entry */
397 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
400 SingleEntry
.Count
= 1;
401 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
403 /* Use this as the import list */
404 ImportList
= &SingleEntry
;
407 /* Loop the import list */
408 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
411 LdrEntry
= ImportList
->Entry
[i
];
412 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
414 /* Skip boot loaded images */
415 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
417 /* Dereference the entry */
418 ASSERT(LdrEntry
->LoadCount
>= 1);
419 if (!--LdrEntry
->LoadCount
)
421 /* Save the import data in case unload fails */
422 CurrentImports
= LdrEntry
->LoadedImports
;
424 /* This is the last entry */
425 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
426 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
428 /* Unloading worked, parse this DLL's imports too */
429 MiDereferenceImports(CurrentImports
);
431 /* Check if we had valid imports */
432 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
433 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
434 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
437 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
442 /* Unload failed, restore imports */
443 LdrEntry
->LoadedImports
= CurrentImports
;
449 return STATUS_SUCCESS
;
454 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
458 /* Check if there's no imports or we're a boot driver or only one entry */
459 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
460 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
461 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
467 /* Otherwise, free the import list */
468 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
469 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
474 MiFindExportedRoutineByName(IN PVOID DllBase
,
475 IN PANSI_STRING ExportName
)
478 PUSHORT OrdinalTable
;
479 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
480 LONG Low
= 0, Mid
= 0, High
, Ret
;
487 /* Get the export directory */
488 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
490 IMAGE_DIRECTORY_ENTRY_EXPORT
,
492 if (!ExportDirectory
) return NULL
;
494 /* Setup name tables */
495 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
496 ExportDirectory
->AddressOfNames
);
497 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
498 ExportDirectory
->AddressOfNameOrdinals
);
500 /* Do a binary search */
501 High
= ExportDirectory
->NumberOfNames
- 1;
504 /* Get new middle value */
505 Mid
= (Low
+ High
) >> 1;
508 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
526 /* Check if we couldn't find it */
527 if (High
< Low
) return NULL
;
529 /* Otherwise, this is the ordinal */
530 Ordinal
= OrdinalTable
[Mid
];
532 /* Validate the ordinal */
533 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
535 /* Resolve the address and write it */
536 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
537 ExportDirectory
->AddressOfFunctions
);
538 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
541 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
542 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
548 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
553 /* Acquire module list lock */
554 KeEnterCriticalRegion();
555 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
557 /* Acquire the spinlock too as we will insert or remove the entry */
558 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
560 /* Insert or remove from the list */
561 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
562 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
565 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
566 ExReleaseResourceLite(&PsLoadedModuleResource
);
567 KeLeaveCriticalRegion();
573 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
578 ULONG_PTR OldBaseTop
, Delta
;
579 PLDR_DATA_TABLE_ENTRY LdrEntry
;
580 PLIST_ENTRY NextEntry
;
583 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
584 // since a real version of Windows would fail at this point, but they seem
585 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
586 // a feature which isn't even used by Windows. Priorities, priorities...
587 // Please note that Microsoft WDK EULA and license prohibits using
588 // the information contained within it for the generation of "non-Windows"
589 // drivers, which is precisely what LD will generate, since an LD driver
590 // will not load on Windows.
592 #ifdef _WORKING_LINKER_
595 PULONG_PTR ImageThunk
;
596 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
598 /* Calculate the top and delta */
599 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
600 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
602 /* Loop the loader block */
603 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
604 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
605 NextEntry
= NextEntry
->Flink
)
607 /* Get the loader entry */
608 LdrEntry
= CONTAINING_RECORD(NextEntry
,
609 LDR_DATA_TABLE_ENTRY
,
611 #ifdef _WORKING_LINKER_
613 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
615 IMAGE_DIRECTORY_ENTRY_IAT
,
617 if (!ImageThunk
) continue;
619 /* Make sure we have an IAT */
620 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
621 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
623 /* Check if it's within this module */
624 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
627 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
628 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
629 *ImageThunk
+= Delta
;
633 /* Get the import table */
634 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
636 IMAGE_DIRECTORY_ENTRY_IMPORT
,
638 if (!ImportDescriptor
) continue;
640 /* Make sure we have an IAT */
641 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
642 while ((ImportDescriptor
->Name
) &&
643 (ImportDescriptor
->OriginalFirstThunk
))
645 /* Get the image thunk */
646 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
647 ImportDescriptor
->FirstThunk
);
650 /* Check if it's within this module */
651 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
654 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
655 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
656 *ImageThunk
+= Delta
;
659 /* Go to the next thunk */
663 /* Go to the next import */
672 MiSnapThunk(IN PVOID DllBase
,
674 IN PIMAGE_THUNK_DATA Name
,
675 IN PIMAGE_THUNK_DATA Address
,
676 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
678 IN BOOLEAN SnapForwarder
,
679 OUT PCHAR
*MissingApi
)
684 PUSHORT OrdinalTable
;
685 PIMAGE_IMPORT_BY_NAME NameImport
;
687 ULONG Low
= 0, Mid
= 0, High
;
690 PCHAR MissingForwarder
;
691 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
694 UNICODE_STRING ForwarderName
;
695 PLIST_ENTRY NextEntry
;
696 PLDR_DATA_TABLE_ENTRY LdrEntry
;
697 ULONG ForwardExportSize
;
698 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
699 PIMAGE_IMPORT_BY_NAME ForwardName
;
700 SIZE_T ForwardLength
;
701 IMAGE_THUNK_DATA ForwardThunk
;
704 /* Check if this is an ordinal */
705 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
706 if ((IsOrdinal
) && !(SnapForwarder
))
708 /* Get the ordinal number and set it as missing */
709 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
710 ExportDirectory
->Base
);
711 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
715 /* Get the VA if we don't have to snap */
716 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
717 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
719 /* Copy the procedure name */
720 RtlStringCbCopyA(*MissingApi
,
721 MAXIMUM_FILENAME_LENGTH
,
722 (PCHAR
)&NameImport
->Name
[0]);
724 /* Setup name tables */
725 DPRINT("Import name: %s\n", NameImport
->Name
);
726 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
727 ExportDirectory
->AddressOfNames
);
728 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
729 ExportDirectory
->AddressOfNameOrdinals
);
731 /* Get the hint and check if it's valid */
732 Hint
= NameImport
->Hint
;
733 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
734 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
736 /* We have a match, get the ordinal number from here */
737 Ordinal
= OrdinalTable
[Hint
];
741 /* Do a binary search */
742 High
= ExportDirectory
->NumberOfNames
- 1;
745 /* Get new middle value */
746 Mid
= (Low
+ High
) >> 1;
749 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
767 /* Check if we couldn't find it */
770 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
771 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
774 /* Otherwise, this is the ordinal */
775 Ordinal
= OrdinalTable
[Mid
];
779 /* Check if the ordinal is invalid */
780 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
783 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
787 /* In case the forwarder is missing */
788 MissingForwarder
= NameBuffer
;
790 /* Resolve the address and write it */
791 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
792 ExportDirectory
->AddressOfFunctions
);
793 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
795 /* Assume success from now on */
796 Status
= STATUS_SUCCESS
;
798 /* Check if the function is actually a forwarder */
799 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
800 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
802 /* Now assume failure in case the forwarder doesn't exist */
803 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
805 /* Build the forwarder name */
806 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
807 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
810 DllName
.MaximumLength
= DllName
.Length
;
813 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
817 /* We failed, just return an error */
821 /* Loop the module list */
822 NextEntry
= PsLoadedModuleList
.Flink
;
823 while (NextEntry
!= &PsLoadedModuleList
)
825 /* Get the loader entry */
826 LdrEntry
= CONTAINING_RECORD(NextEntry
,
827 LDR_DATA_TABLE_ENTRY
,
830 /* Check if it matches */
831 if (RtlPrefixString((PSTRING
)&ForwarderName
,
832 (PSTRING
)&LdrEntry
->BaseDllName
,
835 /* Get the forwarder export directory */
836 ForwardExportDirectory
=
837 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
839 IMAGE_DIRECTORY_ENTRY_EXPORT
,
841 if (!ForwardExportDirectory
) break;
843 /* Allocate a name entry */
844 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
846 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
847 sizeof(*ForwardName
) +
850 if (!ForwardName
) break;
853 RtlCopyMemory(&ForwardName
->Name
[0],
854 DllName
.Buffer
+ DllName
.Length
,
856 ForwardName
->Hint
= 0;
858 /* Set the new address */
859 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
861 /* Snap the forwarder */
862 Status
= MiSnapThunk(LdrEntry
->DllBase
,
866 ForwardExportDirectory
,
871 /* Free the forwarder name and set the thunk */
872 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
873 Address
->u1
= ForwardThunk
.u1
;
877 /* Go to the next entry */
878 NextEntry
= NextEntry
->Flink
;
882 RtlFreeUnicodeString(&ForwarderName
);
892 MmUnloadSystemImage(IN PVOID ImageHandle
)
894 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
895 PVOID BaseAddress
= LdrEntry
->DllBase
;
898 BOOLEAN HadEntry
= FALSE
;
900 /* Acquire the loader lock */
901 KeEnterCriticalRegion();
902 KeWaitForSingleObject(&MmSystemLoadLock
,
908 /* Check if this driver was loaded at boot and didn't get imports parsed */
909 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
911 /* We should still be alive */
912 ASSERT(LdrEntry
->LoadCount
!= 0);
913 LdrEntry
->LoadCount
--;
915 /* Check if we're still loaded */
916 if (LdrEntry
->LoadCount
) goto Done
;
918 /* We should cleanup... are symbols loaded */
919 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
921 /* Create the ANSI name */
922 Status
= RtlUnicodeStringToAnsiString(&TempName
,
923 &LdrEntry
->BaseDllName
,
925 if (NT_SUCCESS(Status
))
927 /* Unload the symbols */
928 DbgUnLoadImageSymbols(&TempName
,
930 (ULONG_PTR
)ZwCurrentProcess());
931 RtlFreeAnsiString(&TempName
);
935 /* FIXME: Free the driver */
936 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
937 //MmFreeSection(LdrEntry->DllBase);
939 /* Check if we're linked in */
940 if (LdrEntry
->InLoadOrderLinks
.Flink
)
943 MiProcessLoaderEntry(LdrEntry
, FALSE
);
947 /* Dereference and clear the imports */
948 MiDereferenceImports(LdrEntry
->LoadedImports
);
949 MiClearImports(LdrEntry
);
951 /* Check if the entry needs to go away */
954 /* Check if it had a name */
955 if (LdrEntry
->FullDllName
.Buffer
)
958 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
961 /* Check if we had a section */
962 if (LdrEntry
->SectionPointer
)
965 ObDereferenceObject(LdrEntry
->SectionPointer
);
969 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
972 /* Release the system lock and return */
974 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
975 KeLeaveCriticalRegion();
976 return STATUS_SUCCESS
;
981 MiResolveImageReferences(IN PVOID ImageBase
,
982 IN PUNICODE_STRING ImageFileDirectory
,
983 IN PUNICODE_STRING NamePrefix OPTIONAL
,
984 OUT PCHAR
*MissingApi
,
985 OUT PWCHAR
*MissingDriver
,
986 OUT PLOAD_IMPORTS
*LoadImports
)
988 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
989 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
990 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
991 PLOAD_IMPORTS LoadedImports
, NewImports
;
992 ULONG GdiLink
, NormalLink
, i
;
993 BOOLEAN ReferenceNeeded
, Loaded
;
994 ANSI_STRING TempString
;
995 UNICODE_STRING NameString
, DllName
;
996 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
997 PVOID ImportBase
, DllBase
;
998 PLIST_ENTRY NextEntry
;
999 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1001 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1003 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1004 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1006 /* Assume no imports */
1007 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1009 /* Get the import descriptor */
1010 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1012 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1014 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1016 /* Loop all imports to count them */
1017 for (CurrentImport
= ImportDescriptor
;
1018 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1025 /* Make sure we have non-zero imports */
1028 /* Calculate and allocate the list we'll need */
1029 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1030 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1036 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1037 LoadedImports
->Count
= ImportCount
;
1043 LoadedImports
= NULL
;
1046 /* Reset the import count and loop descriptors again */
1047 ImportCount
= GdiLink
= NormalLink
= 0;
1048 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1051 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1053 /* Check if this is a GDI driver */
1055 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1057 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1058 NormalLink
= NormalLink
|
1059 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1060 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1061 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1062 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1064 /* Check if this is a valid GDI driver */
1065 if ((GdiLink
) && (NormalLink
))
1067 /* It's not, it's importing stuff it shouldn't be! */
1068 MiDereferenceImports(LoadedImports
);
1069 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1070 return STATUS_PROCEDURE_NOT_FOUND
;
1073 /* Check for user-mode printer or video card drivers, which don't belong */
1074 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1075 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1076 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1077 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1078 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1079 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1081 /* This is not kernel code */
1082 MiDereferenceImports(LoadedImports
);
1083 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1084 return STATUS_PROCEDURE_NOT_FOUND
;
1087 /* Check if this is a "core" import, which doesn't get referenced */
1088 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1089 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1090 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1092 /* Don't reference this */
1093 ReferenceNeeded
= FALSE
;
1097 /* Reference these modules */
1098 ReferenceNeeded
= TRUE
;
1101 /* Now setup a unicode string for the import */
1102 RtlInitAnsiString(&TempString
, ImportName
);
1103 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1104 if (!NT_SUCCESS(Status
))
1107 MiDereferenceImports(LoadedImports
);
1108 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1112 /* We don't support name prefixes yet */
1113 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1115 /* Remember that we haven't loaded the import at this point */
1120 /* Loop the driver list */
1121 NextEntry
= PsLoadedModuleList
.Flink
;
1122 while (NextEntry
!= &PsLoadedModuleList
)
1124 /* Get the loader entry and compare the name */
1125 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1126 LDR_DATA_TABLE_ENTRY
,
1128 if (RtlEqualUnicodeString(&NameString
,
1129 &LdrEntry
->BaseDllName
,
1132 /* Get the base address */
1133 ImportBase
= LdrEntry
->DllBase
;
1135 /* Check if we haven't loaded yet, and we need references */
1136 if (!(Loaded
) && (ReferenceNeeded
))
1138 /* Make sure we're not already loading */
1139 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1141 /* Increase the load count */
1142 LdrEntry
->LoadCount
++;
1146 /* Done, break out */
1150 /* Go to the next entry */
1151 NextEntry
= NextEntry
->Flink
;
1154 /* Check if we haven't loaded the import yet */
1157 /* Setup the import DLL name */
1158 DllName
.MaximumLength
= NameString
.Length
+
1159 ImageFileDirectory
->Length
+
1160 sizeof(UNICODE_NULL
);
1161 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1162 DllName
.MaximumLength
,
1166 /* Setup the base length and copy it */
1167 DllName
.Length
= ImageFileDirectory
->Length
;
1168 RtlCopyMemory(DllName
.Buffer
,
1169 ImageFileDirectory
->Buffer
,
1170 ImageFileDirectory
->Length
);
1172 /* Now add the import name and null-terminate it */
1173 RtlAppendUnicodeStringToString(&DllName
,
1175 DllName
.Buffer
[DllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1177 /* Load the image */
1178 Status
= MmLoadSystemImage(&DllName
,
1184 if (NT_SUCCESS(Status
))
1186 /* We can free the DLL Name */
1187 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1191 /* Fill out the information for the error */
1192 *MissingDriver
= DllName
.Buffer
;
1193 *(PULONG
)MissingDriver
|= 1;
1196 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1201 /* We're out of resources */
1202 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1205 /* Check if we're OK until now */
1206 if (NT_SUCCESS(Status
))
1208 /* We're now loaded */
1212 ASSERT(DllBase
== DllEntry
->DllBase
);
1214 /* Call the initialization routines */
1215 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1216 if (!NT_SUCCESS(Status
))
1218 /* We failed, unload the image */
1219 MmUnloadSystemImage(DllEntry
);
1220 DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status
);
1221 ASSERT(FALSE
); // while (TRUE);
1226 /* Check if we failed by here */
1227 if (!NT_SUCCESS(Status
))
1229 /* Cleanup and return */
1230 RtlFreeUnicodeString(&NameString
);
1231 MiDereferenceImports(LoadedImports
);
1232 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1236 /* Loop again to make sure that everything is OK */
1240 /* Check if we're support to reference this import */
1241 if ((ReferenceNeeded
) && (LoadedImports
))
1243 /* Make sure we're not already loading */
1244 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1247 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1252 /* Free the import name */
1253 RtlFreeUnicodeString(&NameString
);
1255 /* Set the missing driver name and get the export directory */
1256 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1257 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1259 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1261 if (!ExportDirectory
)
1263 /* Cleanup and return */
1264 MiDereferenceImports(LoadedImports
);
1265 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1266 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1267 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1270 /* Make sure we have an IAT */
1271 if (ImportDescriptor
->OriginalFirstThunk
)
1273 /* Get the first thunks */
1274 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1275 ImportDescriptor
->OriginalFirstThunk
);
1276 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1277 ImportDescriptor
->FirstThunk
);
1280 while (OrigThunk
->u1
.AddressOfData
)
1283 Status
= MiSnapThunk(ImportBase
,
1291 if (!NT_SUCCESS(Status
))
1293 /* Cleanup and return */
1294 MiDereferenceImports(LoadedImports
);
1295 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1299 /* Reset the buffer */
1300 *MissingApi
= MissingApiBuffer
;
1304 /* Go to the next import */
1308 /* Check if we have an import list */
1311 /* Reset the count again, and loop entries */
1313 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1315 if (LoadedImports
->Entry
[i
])
1317 /* Got an entry, OR it with 1 in case it's the single entry */
1318 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1319 MM_SYSLDR_SINGLE_ENTRY
);
1324 /* Check if we had no imports */
1327 /* Free the list and set it to no imports */
1328 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1329 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1331 else if (ImportCount
== 1)
1333 /* Just one entry, we can free the table and only use our entry */
1334 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1335 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1337 else if (ImportCount
!= LoadedImports
->Count
)
1339 /* Allocate a new list */
1340 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1341 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1347 NewImports
->Count
= 0;
1349 /* Loop all the imports */
1350 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1352 /* Make sure it's valid */
1353 if (LoadedImports
->Entry
[i
])
1356 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1357 NewImports
->Count
++;
1361 /* Free the old copy */
1362 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1363 LoadedImports
= NewImports
;
1367 /* Return the list */
1368 *LoadImports
= LoadedImports
;
1371 /* Return success */
1372 return STATUS_SUCCESS
;
1377 MiFreeInitializationCode(IN PVOID InitStart
,
1381 PFN_NUMBER PagesFreed
;
1383 /* Get the start PTE */
1384 PointerPte
= MiAddressToPte(InitStart
);
1385 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1387 /* Compute the number of pages we expect to free */
1388 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
+ 1);
1390 /* Try to actually free them */
1391 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1400 MiFindInitializationCode(OUT PVOID
*StartVa
,
1403 ULONG Size
, SectionCount
, Alignment
;
1404 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1405 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1406 PLIST_ENTRY NextEntry
;
1407 PIMAGE_NT_HEADERS NtHeader
;
1408 PIMAGE_SECTION_HEADER Section
, LastSection
;
1411 /* So we don't free our own code yet */
1412 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1414 /* Assume failure */
1417 /* Enter a critical region while we loop the list */
1418 KeEnterCriticalRegion();
1420 /* Loop all loaded modules */
1421 NextEntry
= PsLoadedModuleList
.Flink
;
1422 while (NextEntry
!= &PsLoadedModuleList
)
1424 /* Get the loader entry and its DLL base */
1425 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1426 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1428 /* Get the NT header */
1429 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1433 NextEntry
= NextEntry
->Flink
;
1437 /* Get the first section, the section count, and scan them all */
1438 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1439 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1441 while (SectionCount
> 0)
1443 /* Assume failure */
1446 /* Is this the INIT section or a discardable section? */
1447 if ((*(PULONG
)Section
->Name
== 'TINI') ||
1448 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1456 /* Pick the biggest size -- either raw or virtual */
1457 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1459 /* Read the section alignment */
1460 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1462 /* Align the start and end addresses appropriately */
1463 InitStart
= DllBase
+ Section
->VirtualAddress
;
1464 InitEnd
= ((Alignment
+ InitStart
+ Size
- 2) & 0xFFFFF000) - 1;
1465 InitStart
= (InitStart
+ (PAGE_SIZE
- 1)) & 0xFFFFF000;
1467 /* Have we reached the last section? */
1468 if (SectionCount
== 1)
1471 LastSection
= Section
;
1475 /* We have not, loop all the sections */
1479 /* Keep going until we find a non-discardable section range */
1482 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1484 /* Discardable, so record it, then keep going */
1485 LastSection
= Section
;
1489 /* Non-contigous discard flag, or no flag, break out */
1493 while (SectionCount
> 1);
1496 /* Have we found a discardable or init section? */
1499 /* Pick the biggest size -- either raw or virtual */
1500 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1502 /* Use this as the end of the section address */
1503 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
- 1;
1505 /* Have we reached the last section yet? */
1506 if (SectionCount
!= 1)
1508 /* Then align this accross the session boundary */
1509 InitEnd
= ((Alignment
+ InitEnd
- 1) & 0XFFFFF000) - 1;
1513 /* Make sure we don't let the init section go past the image */
1514 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1515 if (InitEnd
> ImageEnd
) InitEnd
= (ImageEnd
- 1) | (PAGE_SIZE
- 1);
1517 /* Make sure we have a valid, non-zero init section */
1518 if (InitStart
<= InitEnd
)
1520 /* Make sure we are not within this code itself */
1521 if ((InitCode
>= InitStart
) && (InitCode
<= InitEnd
))
1523 /* Return it, we can't free ourselves now */
1524 ASSERT(*StartVa
== 0);
1525 *StartVa
= (PVOID
)InitStart
;
1526 *EndVa
= (PVOID
)InitEnd
;
1530 /* This isn't us -- go ahead and free it */
1531 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1532 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1537 /* Move to the next section */
1542 /* Move to the next module */
1543 NextEntry
= NextEntry
->Flink
;
1546 /* Leave the critical region and return */
1547 KeLeaveCriticalRegion();
1551 * Note: This function assumes that all discardable sections are at the end of
1552 * the PE file. It searches backwards until it finds the non-discardable section
1556 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1558 PMMPTE StartPte
, EndPte
;
1559 PFN_NUMBER PageCount
;
1562 PIMAGE_NT_HEADERS NtHeader
;
1563 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1566 /* Get the base address and the page count */
1567 DllBase
= LdrEntry
->DllBase
;
1568 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1570 /* Get the last PTE in this image */
1571 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1573 /* Get the NT header */
1574 NtHeader
= RtlImageNtHeader(DllBase
);
1575 if (!NtHeader
) return;
1577 /* Get the last section and loop each section backwards */
1578 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1579 DiscardSection
= NULL
;
1580 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1582 /* Go back a section and check if it's discardable */
1584 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1586 /* It is, select it for freeing */
1587 DiscardSection
= Section
;
1591 /* No more discardable sections exist, bail out */
1596 /* Bail out if there's nothing to free */
1597 if (!DiscardSection
) return;
1599 /* Push the DLL base to the first disacrable section, and get its PTE */
1600 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1601 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1602 StartPte
= MiAddressToPte(DllBase
);
1604 /* Check how many pages to free total */
1605 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1606 if (!PageCount
) return;
1608 /* Delete this many PTEs */
1609 PagesDeleted
= MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1615 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1617 PLIST_ENTRY NextEntry
;
1619 PIMAGE_NT_HEADERS NtHeader
;
1620 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1621 PIMAGE_FILE_HEADER FileHeader
;
1622 BOOLEAN ValidRelocs
;
1623 PIMAGE_DATA_DIRECTORY DataDirectory
;
1624 PVOID DllBase
, NewImageAddress
;
1626 PMMPTE PointerPte
, StartPte
, LastPte
;
1629 MMPTE TempPte
, OldPte
;
1631 /* Loop driver list */
1632 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1633 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1634 NextEntry
= NextEntry
->Flink
)
1636 /* Get the loader entry and NT header */
1637 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1638 LDR_DATA_TABLE_ENTRY
,
1640 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1643 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1645 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1646 &LdrEntry
->FullDllName
);
1648 /* Get the first PTE and the number of PTEs we'll need */
1649 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1650 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1651 LastPte
= StartPte
+ PteCount
;
1655 while (PointerPte
< LastPte
)
1658 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1659 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1660 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1661 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1665 /* Skip kernel and HAL */
1666 /* ROS HACK: Skip BOOTVID/KDCOM too */
1668 if (i
<= 4) continue;
1670 /* Skip non-drivers */
1671 if (!NtHeader
) continue;
1673 /* Get the file header and make sure we can relocate */
1674 FileHeader
= &NtHeader
->FileHeader
;
1675 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1676 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1677 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1679 /* Everything made sense until now, check the relocation section too */
1680 DataDirectory
= &NtHeader
->OptionalHeader
.
1681 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1682 if (!DataDirectory
->VirtualAddress
)
1684 /* We don't really have relocations */
1685 ValidRelocs
= FALSE
;
1689 /* Make sure the size is valid */
1690 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1691 LdrEntry
->SizeOfImage
)
1693 /* They're not, skip */
1697 /* We have relocations */
1701 /* Remember the original address */
1702 DllBase
= LdrEntry
->DllBase
;
1705 PointerPte
= StartPte
;
1706 while (PointerPte
< LastPte
)
1708 /* Mark the page modified in the PFN database */
1709 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1710 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1711 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1712 Pfn1
->u3
.e1
.Modified
= TRUE
;
1718 /* Now reserve system PTEs for the image */
1719 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1722 /* Shouldn't happen */
1723 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1724 ASSERT(FALSE
); // while (TRUE);
1728 /* This is the new virtual address for the module */
1729 LastPte
= PointerPte
+ PteCount
;
1730 NewImageAddress
= MiPteToAddress(PointerPte
);
1733 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1734 ASSERT(ExpInitializationPhase
== 0);
1736 /* Loop the new driver PTEs */
1737 TempPte
= ValidKernelPte
;
1738 while (PointerPte
< LastPte
)
1740 /* Copy the old data */
1742 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1744 /* Set page number from the loader's memory */
1745 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1748 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1755 /* Update position */
1756 PointerPte
-= PteCount
;
1759 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1761 /* Set the image base to the address where the loader put it */
1762 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1764 /* Check if we had relocations */
1767 /* Relocate the image */
1768 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1772 STATUS_CONFLICTING_ADDRESSES
,
1773 STATUS_INVALID_IMAGE_FORMAT
);
1774 if (!NT_SUCCESS(Status
))
1776 /* This shouldn't happen */
1777 DPRINT1("Relocations failed!\n");
1778 ASSERT(FALSE
); // while (TRUE);
1783 /* Update the loader entry */
1784 LdrEntry
->DllBase
= NewImageAddress
;
1786 /* Update the thunks */
1787 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1788 MiUpdateThunks(LoaderBlock
,
1791 LdrEntry
->SizeOfImage
);
1793 /* Update the loader entry */
1794 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1795 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1796 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1797 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1799 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1806 MiBuildImportsForBootDrivers(VOID
)
1808 PLIST_ENTRY NextEntry
, NextEntry2
;
1809 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1810 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1811 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1812 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1813 PLOAD_IMPORTS LoadedImports
;
1814 ULONG LoadedImportsSize
, ImportSize
;
1815 PULONG_PTR ImageThunk
;
1816 ULONG_PTR DllBase
, DllEnd
;
1817 ULONG Modules
= 0, i
, j
= 0;
1818 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1820 /* Initialize variables */
1821 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1823 /* Loop the loaded module list... we are early enough that no lock is needed */
1824 NextEntry
= PsLoadedModuleList
.Flink
;
1825 while (NextEntry
!= &PsLoadedModuleList
)
1828 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1829 LDR_DATA_TABLE_ENTRY
,
1832 /* Check if it's the kernel or HAL */
1833 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1836 KernelEntry
= LdrEntry
;
1838 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1841 HalEntry
= LdrEntry
;
1844 /* Check if this is a driver DLL */
1845 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1847 /* Check if this is the HAL or kernel */
1848 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1850 /* Add a reference */
1851 LdrEntry
->LoadCount
= 1;
1855 /* No referencing needed */
1856 LdrEntry
->LoadCount
= 0;
1861 /* No referencing needed */
1862 LdrEntry
->LoadCount
= 0;
1865 /* Remember this came from the loader */
1866 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1869 NextEntry
= NextEntry
->Flink
;
1873 /* We must have at least found the kernel and HAL */
1874 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1876 /* Allocate the list */
1877 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1878 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1880 /* Loop the loaded module list again */
1881 NextEntry
= PsLoadedModuleList
.Flink
;
1882 while (NextEntry
!= &PsLoadedModuleList
)
1885 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1886 LDR_DATA_TABLE_ENTRY
,
1888 #ifdef _WORKING_LOADER_
1889 /* Get its imports */
1890 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1892 IMAGE_DIRECTORY_ENTRY_IAT
,
1896 /* Get its imports */
1897 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1899 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1901 if (!ImportDescriptor
)
1905 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1906 NextEntry
= NextEntry
->Flink
;
1910 /* Clear the list and count the number of IAT thunks */
1911 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1912 #ifdef _WORKING_LOADER_
1913 ImportSize
/= sizeof(ULONG_PTR
);
1915 /* Scan the thunks */
1916 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1918 DllBase
= DllEnd
= i
= 0;
1919 while ((ImportDescriptor
->Name
) &&
1920 (ImportDescriptor
->OriginalFirstThunk
))
1922 /* Get the image thunk */
1923 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1924 ImportDescriptor
->FirstThunk
);
1928 /* Do we already have an address? */
1931 /* Is the thunk in the same address? */
1932 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1934 /* Skip it, we already have a reference for it */
1935 ASSERT(EntryArray
[j
]);
1941 /* Loop the loaded module list to locate this address owner */
1943 NextEntry2
= PsLoadedModuleList
.Flink
;
1944 while (NextEntry2
!= &PsLoadedModuleList
)
1947 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1948 LDR_DATA_TABLE_ENTRY
,
1951 /* Get the address range for this module */
1952 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1953 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1955 /* Check if this IAT entry matches it */
1956 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1959 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1960 EntryArray
[j
] = LdrEntry2
;
1964 /* Keep searching */
1965 NextEntry2
= NextEntry2
->Flink
;
1969 /* Do we have a thunk outside the range? */
1970 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1975 /* Should not be happening */
1976 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1977 LdrEntry
, ImageThunk
, *ImageThunk
);
1981 /* Reset if we hit this */
1984 #ifndef _WORKING_LOADER_
1993 /* Now scan how many imports we really have */
1994 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1996 /* Skip HAL and kernel */
1997 if ((EntryArray
[i
]) &&
1998 (EntryArray
[i
] != HalEntry
) &&
1999 (EntryArray
[i
] != KernelEntry
))
2001 /* A valid reference */
2002 LastEntry
= EntryArray
[i
];
2007 /* Do we have any imports after all? */
2011 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2013 else if (ImportSize
== 1)
2015 /* A single entry import */
2016 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2017 LastEntry
->LoadCount
++;
2021 /* We need an import table */
2022 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2023 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2026 ASSERT(LoadedImports
);
2028 /* Save the count */
2029 LoadedImports
->Count
= ImportSize
;
2031 /* Now copy all imports */
2032 for (i
= 0, j
= 0; i
< Modules
; i
++)
2034 /* Skip HAL and kernel */
2035 if ((EntryArray
[i
]) &&
2036 (EntryArray
[i
] != HalEntry
) &&
2037 (EntryArray
[i
] != KernelEntry
))
2039 /* A valid reference */
2040 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2041 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2042 EntryArray
[i
]->LoadCount
++;
2047 /* Should had as many entries as we expected */
2048 ASSERT(j
== ImportSize
);
2049 LdrEntry
->LoadedImports
= LoadedImports
;
2053 NextEntry
= NextEntry
->Flink
;
2056 /* Free the initial array */
2057 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2059 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2061 /* Kernel and HAL are loaded at boot */
2062 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2063 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2065 /* All worked well */
2066 return STATUS_SUCCESS
;
2072 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2075 PIMAGE_NT_HEADERS NtHeaders
;
2076 PIMAGE_SECTION_HEADER SectionHeader
;
2077 ULONG Sections
, Size
;
2079 /* Get the kernel section header */
2080 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2081 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2082 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2084 /* Loop all the sections */
2085 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2088 /* Grab the size of the section */
2089 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2091 /* Check for .RSRC section */
2092 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2094 /* Remember the PTEs so we can modify them later */
2095 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2096 SectionHeader
->VirtualAddress
);
2097 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2098 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2100 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2102 /* POOLCODE vs. POOLMI */
2103 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2105 /* Found Ex* Pool code */
2106 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2107 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2109 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2111 /* Found Mm* Pool code */
2112 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2113 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2116 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2117 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2119 /* Found MISYSPTE (Mm System PTE code)*/
2120 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2121 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2133 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2135 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2136 PLIST_ENTRY ListHead
, NextEntry
;
2139 /* Setup the loaded module list and locks */
2140 ExInitializeResourceLite(&PsLoadedModuleResource
);
2141 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2142 InitializeListHead(&PsLoadedModuleList
);
2144 /* Get loop variables and the kernel entry */
2145 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2146 NextEntry
= ListHead
->Flink
;
2147 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2148 LDR_DATA_TABLE_ENTRY
,
2150 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2152 /* Locate resource section, pool code, and system pte code */
2153 MiLocateKernelSections(LdrEntry
);
2155 /* Loop the loader block */
2156 while (NextEntry
!= ListHead
)
2158 /* Get the loader entry */
2159 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2160 LDR_DATA_TABLE_ENTRY
,
2163 /* FIXME: ROS HACK. Make sure this is a driver */
2164 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2166 /* Skip this entry */
2167 NextEntry
= NextEntry
->Flink
;
2171 /* Calculate the size we'll need and allocate a copy */
2172 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2173 LdrEntry
->BaseDllName
.MaximumLength
+
2174 sizeof(UNICODE_NULL
);
2175 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2176 if (!NewEntry
) return FALSE
;
2178 /* Copy the entry over */
2179 *NewEntry
= *LdrEntry
;
2181 /* Allocate the name */
2182 NewEntry
->FullDllName
.Buffer
=
2183 ExAllocatePoolWithTag(PagedPool
,
2184 LdrEntry
->FullDllName
.MaximumLength
+
2185 sizeof(UNICODE_NULL
),
2187 if (!NewEntry
->FullDllName
.Buffer
)
2189 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2193 /* Set the base name */
2194 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2196 /* Copy the full and base name */
2197 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2198 LdrEntry
->FullDllName
.Buffer
,
2199 LdrEntry
->FullDllName
.MaximumLength
);
2200 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2201 LdrEntry
->BaseDllName
.Buffer
,
2202 LdrEntry
->BaseDllName
.MaximumLength
);
2204 /* Null-terminate the base name */
2205 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2206 sizeof(WCHAR
)] = UNICODE_NULL
;
2208 /* Insert the entry into the list */
2209 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2210 NextEntry
= NextEntry
->Flink
;
2213 /* Build the import lists for the boot drivers */
2214 MiBuildImportsForBootDrivers();
2222 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2223 IN OUT PVOID
*ImageBaseAddress
,
2224 IN PUNICODE_STRING BaseImageName
,
2225 IN BOOLEAN BootDriver
)
2227 PLIST_ENTRY NextEntry
;
2228 BOOLEAN DriverFound
= FALSE
;
2229 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2230 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2231 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2234 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2235 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2238 /* Make sure there's enough system PTEs for a large page driver */
2239 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2244 /* This happens if the registry key had a "*" (wildcard) in it */
2245 if (MiLargePageAllDrivers
== 0)
2247 /* It didn't, so scan the list */
2248 NextEntry
= MiLargePageDriverList
.Flink
;
2249 while (NextEntry
!= &MiLargePageDriverList
)
2251 /* Check if the driver name matches */
2252 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2253 MI_LARGE_PAGE_DRIVER_ENTRY
,
2255 if (RtlEqualUnicodeString(BaseImageName
,
2256 &LargePageDriverEntry
->BaseName
,
2259 /* Enable large pages for this driver */
2265 NextEntry
= NextEntry
->Flink
;
2268 /* If we didn't find the driver, it doesn't need large pages */
2269 if (DriverFound
== FALSE
) return FALSE
;
2272 /* Nothing to do yet */
2273 DPRINT1("Large pages not supported!\n");
2279 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2280 IN ULONG SectionProtection
)
2282 ULONG Protection
= MM_ZERO_ACCESS
;
2284 /* Check if the caller gave anything */
2285 if (SectionProtection
)
2287 /* Always turn on execute access */
2288 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2290 /* Check if the registry setting is on or not */
2291 if (!MmEnforceWriteProtection
)
2293 /* Turn on write access too */
2294 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2298 /* Convert to internal PTE flags */
2299 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2300 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2302 /* Check for write access */
2303 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2305 /* Session space is not supported */
2308 DPRINT1("Session drivers not supported\n");
2309 ASSERT(SessionSpace
== FALSE
);
2313 /* Convert to internal PTE flag */
2314 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2318 /* If there's no access at all by now, convert to internal no access flag */
2319 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2321 /* Return the computed PTE protection */
2327 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2329 IN ULONG ProtectionMask
)
2331 /* I'm afraid to introduce regressions at the moment... */
2337 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2339 PIMAGE_NT_HEADERS NtHeaders
;
2340 PIMAGE_SECTION_HEADER Section
;
2341 PFN_NUMBER DriverPages
;
2342 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2343 ULONG Sections
, Size
;
2344 ULONG_PTR BaseAddress
, CurrentAddress
;
2345 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2346 ULONG CurrentMask
, CombinedMask
= 0;
2349 /* No need to write protect physical memory-backed drivers (large pages) */
2350 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2352 /* Get the image headers */
2353 NtHeaders
= RtlImageNtHeader(ImageBase
);
2354 if (!NtHeaders
) return;
2356 /* Check if this is a session driver or not */
2357 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2359 /* Don't touch NT4 drivers */
2360 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2361 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2366 DPRINT1("Session drivers not supported\n");
2370 /* These are the only protection masks we care about */
2371 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2373 /* Calculate the number of pages this driver is occupying */
2374 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2376 /* Get the number of sections and the first section header */
2377 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2378 ASSERT(Sections
!= 0);
2379 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2381 /* Loop all the sections */
2382 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2385 /* Get the section size */
2386 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2388 /* Get its virtual address */
2389 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2390 if (BaseAddress
< CurrentAddress
)
2392 /* Windows doesn't like these */
2393 DPRINT1("Badly linked image!\n");
2397 /* Remember the current address */
2398 CurrentAddress
= BaseAddress
+ Size
- 1;
2405 /* Get the number of sections and the first section header */
2406 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2407 ASSERT(Sections
!= 0);
2408 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2410 /* Set the address at the end to initialize the loop */
2411 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2412 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2414 /* Set the PTE points for the image, and loop its sections */
2415 StartPte
= MiAddressToPte(ImageBase
);
2416 LastPte
= StartPte
+ DriverPages
;
2419 /* Get the section size */
2420 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2422 /* Get its virtual address and PTE */
2423 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2424 PointerPte
= MiAddressToPte(BaseAddress
);
2426 /* Check if we were already protecting a run, and found a new run */
2427 if ((ComboPte
) && (PointerPte
> ComboPte
))
2429 /* Compute protection */
2430 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2433 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2435 /* Check for overlap */
2436 if (ComboPte
== StartPte
) StartPte
++;
2438 /* One done, reset variables */
2440 CombinedProtection
= 0;
2443 /* Break out when needed */
2444 if (PointerPte
>= LastPte
) break;
2446 /* Get the requested protection from the image header */
2447 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2448 if (SectionProtection
== CurrentProtection
)
2450 /* Same protection, so merge the request */
2451 CurrentAddress
= BaseAddress
+ Size
- 1;
2459 /* This is now a new section, so close up the old one */
2460 CurrentPte
= MiAddressToPte(CurrentAddress
);
2462 /* Check for overlap */
2463 if (CurrentPte
== PointerPte
)
2465 /* Skip the last PTE, since it overlaps with us */
2468 /* And set the PTE we will merge with */
2469 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2470 ComboPte
= PointerPte
;
2472 /* Get the most flexible protection by merging both */
2473 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2476 /* Loop any PTEs left */
2477 if (CurrentPte
>= StartPte
)
2480 ASSERT(StartPte
< LastPte
);
2482 /* Make sure we don't overflow past the last PTE in the driver */
2483 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2484 ASSERT(CurrentPte
>= StartPte
);
2486 /* Compute the protection and set it */
2487 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2488 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2492 StartPte
= PointerPte
;
2493 CurrentAddress
= BaseAddress
+ Size
- 1;
2494 CurrentProtection
= SectionProtection
;
2501 /* Is there a leftover section to merge? */
2504 /* Compute and set the protection */
2505 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2506 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2508 /* Handle overlap */
2509 if (ComboPte
== StartPte
) StartPte
++;
2512 /* Finally, handle the last section */
2513 CurrentPte
= MiAddressToPte(CurrentAddress
);
2514 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2516 /* Handle overlap */
2517 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2518 ASSERT(CurrentPte
>= StartPte
);
2520 /* Compute and set the protection */
2521 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2522 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2528 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2532 PETHREAD CurrentThread
= PsGetCurrentThread();
2533 PFN_COUNT PageCount
= 0;
2534 PFN_NUMBER PageFrameIndex
;
2538 /* Get the driver's base address */
2539 ImageBase
= MiPteToAddress(PointerPte
);
2540 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2542 /* If this is a large page, it's stuck in physical memory */
2543 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2545 /* Lock the working set */
2546 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2549 while (PointerPte
<= LastPte
)
2551 /* Check for valid PTE */
2552 if (PointerPte
->u
.Hard
.Valid
== 1)
2554 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2555 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2556 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2558 /* No working sets in ReactOS yet */
2562 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2566 /* Release the working set */
2567 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2569 /* Do we have any driver pages? */
2572 /* Update counters */
2573 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2579 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2581 ULONG_PTR ImageBase
;
2582 PIMAGE_NT_HEADERS NtHeaders
;
2583 ULONG Sections
, Alignment
, Size
;
2584 PIMAGE_SECTION_HEADER Section
;
2585 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2586 if (MmDisablePagingExecutive
) return;
2588 /* Get the driver base address and its NT header */
2589 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2590 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2591 if (!NtHeaders
) return;
2593 /* Get the sections and their alignment */
2594 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2595 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2597 /* Loop each section */
2598 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2601 /* Find PAGE or .edata */
2602 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2603 (*(PULONG
)Section
->Name
== 'ade.'))
2605 /* Had we already done some work? */
2608 /* Nope, setup the first PTE address */
2609 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2614 /* Compute the size */
2615 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2617 /* Find the last PTE that maps this section */
2618 LastPte
= MiAddressToPte(ImageBase
+
2619 Section
->VirtualAddress
+
2626 /* Had we found a section before? */
2629 /* Mark it as pageable */
2630 MiSetPagingOfDriver(PointerPte
, LastPte
);
2635 /* Keep searching */
2640 /* Handle the straggler */
2641 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2646 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2648 PIMAGE_NT_HEADERS NtHeader
;
2651 /* Get NT Headers */
2652 NtHeader
= RtlImageNtHeader(BaseAddress
);
2655 /* Check if this image is only safe for UP while we have 2+ CPUs */
2656 if ((KeNumberProcessors
> 1) &&
2657 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2664 /* Otherwise, it's safe */
2670 MmCheckSystemImage(IN HANDLE ImageHandle
,
2671 IN BOOLEAN PurgeSection
)
2674 HANDLE SectionHandle
;
2675 PVOID ViewBase
= NULL
;
2676 SIZE_T ViewSize
= 0;
2677 IO_STATUS_BLOCK IoStatusBlock
;
2678 FILE_STANDARD_INFORMATION FileStandardInfo
;
2679 KAPC_STATE ApcState
;
2680 PIMAGE_NT_HEADERS NtHeaders
;
2681 OBJECT_ATTRIBUTES ObjectAttributes
;
2684 /* Setup the object attributes */
2685 InitializeObjectAttributes(&ObjectAttributes
,
2687 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2691 /* Create a section for the DLL */
2692 Status
= ZwCreateSection(&SectionHandle
,
2693 SECTION_MAP_EXECUTE
,
2699 if (!NT_SUCCESS(Status
))
2701 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2705 /* Make sure we're in the system process */
2706 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2709 Status
= ZwMapViewOfSection(SectionHandle
,
2719 if (!NT_SUCCESS(Status
))
2721 /* We failed, close the handle and return */
2722 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2723 KeUnstackDetachProcess(&ApcState
);
2724 ZwClose(SectionHandle
);
2728 /* Now query image information */
2729 Status
= ZwQueryInformationFile(ImageHandle
,
2732 sizeof(FileStandardInfo
),
2733 FileStandardInformation
);
2734 if (NT_SUCCESS(Status
))
2736 /* First, verify the checksum */
2737 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2742 /* Set checksum failure */
2743 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2747 /* Make sure it's a real image */
2748 NtHeaders
= RtlImageNtHeader(ViewBase
);
2751 /* Set checksum failure */
2752 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2756 /* Make sure it's for the correct architecture */
2757 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2758 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2760 /* Set protection failure */
2761 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2765 /* Check that it's a valid SMP image if we have more then one CPU */
2766 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2768 /* Otherwise it's not the right image */
2769 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2773 /* Unmap the section, close the handle, and return status */
2775 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2776 KeUnstackDetachProcess(&ApcState
);
2777 ZwClose(SectionHandle
);
2783 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2784 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2785 IN PUNICODE_STRING LoadedName OPTIONAL
,
2787 OUT PVOID
*ModuleObject
,
2788 OUT PVOID
*ImageBaseAddress
)
2790 PVOID ModuleLoadBase
= NULL
;
2792 HANDLE FileHandle
= NULL
;
2793 OBJECT_ATTRIBUTES ObjectAttributes
;
2794 IO_STATUS_BLOCK IoStatusBlock
;
2795 PIMAGE_NT_HEADERS NtHeader
;
2796 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2797 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2798 ULONG EntrySize
, DriverSize
;
2799 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2800 PCHAR MissingApiName
, Buffer
;
2801 PWCHAR MissingDriverName
;
2802 HANDLE SectionHandle
;
2803 ACCESS_MASK DesiredAccess
;
2804 PVOID Section
= NULL
;
2805 BOOLEAN LockOwned
= FALSE
;
2806 PLIST_ENTRY NextEntry
;
2807 IMAGE_INFO ImageInfo
;
2811 /* Detect session-load */
2815 ASSERT(NamePrefix
== NULL
);
2816 ASSERT(LoadedName
== NULL
);
2818 /* Make sure the process is in session too */
2819 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2822 /* Allocate a buffer we'll use for names */
2823 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2824 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2826 /* Check for a separator */
2827 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2832 /* Loop the path until we get to the base name */
2833 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2834 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2836 /* Get the length */
2837 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2838 BaseLength
*= sizeof(WCHAR
);
2840 /* Setup the string */
2841 BaseName
.Length
= (USHORT
)BaseLength
;
2842 BaseName
.Buffer
= p
;
2846 /* Otherwise, we already have a base name */
2847 BaseName
.Length
= FileName
->Length
;
2848 BaseName
.Buffer
= FileName
->Buffer
;
2851 /* Setup the maximum length */
2852 BaseName
.MaximumLength
= BaseName
.Length
;
2854 /* Now compute the base directory */
2855 BaseDirectory
= *FileName
;
2856 BaseDirectory
.Length
-= BaseName
.Length
;
2857 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2859 /* And the prefix, which for now is just the name itself */
2860 PrefixName
= *FileName
;
2862 /* Check if we have a prefix */
2863 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2865 /* Check if we already have a name, use it instead */
2866 if (LoadedName
) BaseName
= *LoadedName
;
2868 /* Check for loader snap debugging */
2869 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2871 /* Print out standard string */
2872 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2873 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2876 /* Acquire the load lock */
2878 ASSERT(LockOwned
== FALSE
);
2880 KeEnterCriticalRegion();
2881 KeWaitForSingleObject(&MmSystemLoadLock
,
2887 /* Scan the module list */
2888 NextEntry
= PsLoadedModuleList
.Flink
;
2889 while (NextEntry
!= &PsLoadedModuleList
)
2891 /* Get the entry and compare the names */
2892 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2893 LDR_DATA_TABLE_ENTRY
,
2895 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2897 /* Found it, break out */
2902 NextEntry
= NextEntry
->Flink
;
2905 /* Check if we found the image */
2906 if (NextEntry
!= &PsLoadedModuleList
)
2908 /* Check if we had already mapped a section */
2911 /* Dereference and clear */
2912 ObDereferenceObject(Section
);
2916 /* Check if this was supposed to be a session load */
2919 /* It wasn't, so just return the data */
2920 *ModuleObject
= LdrEntry
;
2921 *ImageBaseAddress
= LdrEntry
->DllBase
;
2922 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2926 /* We don't support session loading yet */
2927 DPRINT1("Unsupported Session-Load!\n");
2928 ASSERT(FALSE
); // while (TRUE);
2929 Status
= STATUS_NOT_IMPLEMENTED
;
2937 /* It wasn't loaded, and we didn't have a previous attempt */
2938 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2939 KeLeaveCriticalRegion();
2942 /* Check if KD is enabled */
2943 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2945 /* FIXME: Attempt to get image from KD */
2948 /* We don't have a valid entry */
2951 /* Setup image attributes */
2952 InitializeObjectAttributes(&ObjectAttributes
,
2954 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2958 /* Open the image */
2959 Status
= ZwOpenFile(&FileHandle
,
2963 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2965 if (!NT_SUCCESS(Status
))
2967 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
2973 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2974 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2975 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2976 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2982 /* Check if this is a session-load */
2985 /* Then we only need read and execute */
2986 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2990 /* Otherwise, we can allow write access */
2991 DesiredAccess
= SECTION_ALL_ACCESS
;
2994 /* Initialize the attributes for the section */
2995 InitializeObjectAttributes(&ObjectAttributes
,
2997 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3001 /* Create the section */
3002 Status
= ZwCreateSection(&SectionHandle
,
3009 if (!NT_SUCCESS(Status
))
3011 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3015 /* Now get the section pointer */
3016 Status
= ObReferenceObjectByHandle(SectionHandle
,
3017 SECTION_MAP_EXECUTE
,
3018 MmSectionObjectType
,
3022 ZwClose(SectionHandle
);
3023 if (!NT_SUCCESS(Status
)) goto Quickie
;
3025 /* Check if this was supposed to be a session-load */
3028 /* We don't support session loading yet */
3029 DPRINT1("Unsupported Session-Load!\n");
3030 ASSERT(FALSE
); // while (TRUE);
3034 /* Check the loader list again, we should end up in the path below */
3039 /* We don't have a valid entry */
3043 /* Load the image */
3044 Status
= MiLoadImageSection(&Section
,
3049 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3051 /* Get the size of the driver */
3052 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
3054 /* Make sure we're not being loaded into session space */
3057 /* Check for success */
3058 if (NT_SUCCESS(Status
))
3060 /* Support large pages for drivers */
3061 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3067 /* Dereference the section */
3068 ObDereferenceObject(Section
);
3072 /* Check for failure of the load earlier */
3073 if (!NT_SUCCESS(Status
))
3075 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3079 /* Relocate the driver */
3080 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3084 STATUS_CONFLICTING_ADDRESSES
,
3085 STATUS_INVALID_IMAGE_FORMAT
);
3086 if (!NT_SUCCESS(Status
))
3088 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3092 /* Get the NT Header */
3093 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3095 /* Calculate the size we'll need for the entry and allocate it */
3096 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3098 sizeof(UNICODE_NULL
);
3100 /* Allocate the entry */
3101 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3105 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3109 /* Setup the entry */
3110 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3111 LdrEntry
->LoadCount
= 1;
3112 LdrEntry
->LoadedImports
= LoadedImports
;
3113 LdrEntry
->PatchInformation
= NULL
;
3115 /* Check the version */
3116 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3117 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3119 /* Mark this image as a native image */
3120 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3123 /* Setup the rest of the entry */
3124 LdrEntry
->DllBase
= ModuleLoadBase
;
3125 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3126 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3127 LdrEntry
->SizeOfImage
= DriverSize
;
3128 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3129 LdrEntry
->SectionPointer
= Section
;
3131 /* Now write the DLL name */
3132 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3133 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3134 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3136 /* Copy and null-terminate it */
3137 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3140 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3142 /* Now allocate the full name */
3143 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3145 sizeof(UNICODE_NULL
),
3147 if (!LdrEntry
->FullDllName
.Buffer
)
3149 /* Don't fail, just set it to zero */
3150 LdrEntry
->FullDllName
.Length
= 0;
3151 LdrEntry
->FullDllName
.MaximumLength
= 0;
3156 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3157 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3159 /* Copy and null-terminate */
3160 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3163 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3167 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3169 /* Resolve imports */
3170 MissingApiName
= Buffer
;
3171 Status
= MiResolveImageReferences(ModuleLoadBase
,
3177 if (!NT_SUCCESS(Status
))
3179 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3182 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3184 /* Check if we need to free the name */
3185 if (LdrEntry
->FullDllName
.Buffer
)
3188 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3191 /* Free the entry itself */
3192 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3197 /* Update the loader entry */
3198 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3199 LDRP_ENTRY_PROCESSED
|
3201 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3202 LdrEntry
->LoadedImports
= LoadedImports
;
3204 /* FIXME: Call driver verifier's loader function */
3206 /* Write-protect the system image */
3207 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3209 /* Check if notifications are enabled */
3210 if (PsImageNotifyEnabled
)
3212 /* Fill out the notification data */
3213 ImageInfo
.Properties
= 0;
3214 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3215 ImageInfo
.SystemModeImage
= TRUE
;
3216 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3217 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3218 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3220 /* Send the notification */
3221 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3224 #if defined(KDBG) || defined(_WINKD_)
3225 /* MiCacheImageSymbols doesn't detect rossym */
3228 /* Check if there's symbols */
3229 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3232 /* Check if the system root is present */
3233 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3234 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3236 /* Add the system root */
3237 UnicodeTemp
= PrefixName
;
3238 UnicodeTemp
.Buffer
+= 11;
3239 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3242 &SharedUserData
->NtSystemRoot
[2],
3247 /* Build the name */
3248 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3251 /* Setup the ansi string */
3252 RtlInitString(&AnsiTemp
, Buffer
);
3254 /* Notify the debugger */
3255 DbgLoadImageSymbols(&AnsiTemp
,
3257 (ULONG_PTR
)ZwCurrentProcess());
3258 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3261 /* Page the driver */
3262 ASSERT(Section
== NULL
);
3263 MiEnablePagingOfDriver(LdrEntry
);
3265 /* Return pointers */
3266 *ModuleObject
= LdrEntry
;
3267 *ImageBaseAddress
= LdrEntry
->DllBase
;
3270 /* Check if we have the lock acquired */
3273 /* Release the lock */
3274 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3275 KeLeaveCriticalRegion();
3279 /* If we have a file handle, close it */
3280 if (FileHandle
) ZwClose(FileHandle
);
3282 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3283 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3285 /* Free the name buffer and return status */
3286 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3290 PLDR_DATA_TABLE_ENTRY
3292 MiLookupDataTableEntry(IN PVOID Address
)
3294 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3295 PLIST_ENTRY NextEntry
;
3299 NextEntry
= PsLoadedModuleList
.Flink
;
3302 /* Get the loader entry */
3303 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3304 LDR_DATA_TABLE_ENTRY
,
3307 /* Check if the address matches */
3308 if ((Address
>= LdrEntry
->DllBase
) &&
3309 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3310 LdrEntry
->SizeOfImage
)))
3313 FoundEntry
= LdrEntry
;
3318 NextEntry
= NextEntry
->Flink
;
3319 } while(NextEntry
!= &PsLoadedModuleList
);
3321 /* Return the entry */
3325 /* PUBLIC FUNCTIONS ***********************************************************/
3332 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3334 PMMPTE StartPte
, EndPte
;
3335 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3338 /* Get the loader entry */
3339 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3340 if (!LdrEntry
) return NULL
;
3342 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3343 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3345 /* Don't do anything, just return the base address */
3346 return LdrEntry
->DllBase
;
3349 /* Wait for active DPCs to finish before we page out the driver */
3350 KeFlushQueuedDpcs();
3352 /* Get the PTE range for the whole driver image */
3353 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3354 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3356 /* Enable paging for the PTE range */
3357 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3358 MiSetPagingOfDriver(StartPte
, EndPte
);
3360 /* Return the base address */
3361 return LdrEntry
->DllBase
;
3369 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3379 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3381 PVOID ProcAddress
= NULL
;
3382 ANSI_STRING AnsiRoutineName
;
3384 PLIST_ENTRY NextEntry
;
3385 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3386 BOOLEAN Found
= FALSE
;
3387 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3388 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3391 /* Convert routine to ansi name */
3392 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3395 if (!NT_SUCCESS(Status
)) return NULL
;
3398 KeEnterCriticalRegion();
3399 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3401 /* Loop the loaded module list */
3402 NextEntry
= PsLoadedModuleList
.Flink
;
3403 while (NextEntry
!= &PsLoadedModuleList
)
3406 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3407 LDR_DATA_TABLE_ENTRY
,
3410 /* Check if it's the kernel or HAL */
3411 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3417 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3424 /* Check if we found a valid binary */
3427 /* Find the procedure name */
3428 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3431 /* Break out if we found it or if we already tried both modules */
3432 if (ProcAddress
) break;
3433 if (Modules
== 2) break;
3437 NextEntry
= NextEntry
->Flink
;
3440 /* Release the lock */
3441 ExReleaseResourceLite(&PsLoadedModuleResource
);
3442 KeLeaveCriticalRegion();
3444 /* Free the string and return */
3445 RtlFreeAnsiString(&AnsiRoutineName
);