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
);
163 DPRINT1("MiReserveSystemPtes failed\n");
164 KeUnstackDetachProcess(&ApcState
);
165 return STATUS_INSUFFICIENT_RESOURCES
;
168 /* New driver base */
169 LastPte
= PointerPte
+ PteCount
;
170 DriverBase
= MiPteToAddress(PointerPte
);
172 /* The driver is here */
173 *ImageBase
= DriverBase
;
174 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName
, DriverBase
, PteCount
);
176 /* Loop the new driver PTEs */
177 TempPte
= ValidKernelPte
;
178 while (PointerPte
< LastPte
)
180 /* Allocate a page */
181 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
185 if (FileName
->Buffer
)
187 pos
= wcsrchr(FileName
->Buffer
, '\\');
188 len
= wcslen(pos
) * sizeof(WCHAR
);
189 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
192 TempPte
.u
.Hard
.PageFrameNumber
= MiAllocatePfn(PointerPte
, MM_EXECUTE
);
195 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
202 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
204 /* Now unmap the view */
205 Status
= MmUnmapViewOfSection(Process
, Base
);
206 ASSERT(NT_SUCCESS(Status
));
208 /* Detach and return status */
209 KeUnstackDetachProcess(&ApcState
);
215 MiLocateExportName(IN PVOID DllBase
,
219 PUSHORT OrdinalTable
;
220 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
221 LONG Low
= 0, Mid
= 0, High
, Ret
;
228 /* Get the export directory */
229 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
231 IMAGE_DIRECTORY_ENTRY_EXPORT
,
233 if (!ExportDirectory
) return NULL
;
235 /* Setup name tables */
236 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
237 ExportDirectory
->AddressOfNames
);
238 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
239 ExportDirectory
->AddressOfNameOrdinals
);
241 /* Do a binary search */
242 High
= ExportDirectory
->NumberOfNames
- 1;
245 /* Get new middle value */
246 Mid
= (Low
+ High
) >> 1;
249 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
267 /* Check if we couldn't find it */
268 if (High
< Low
) return NULL
;
270 /* Otherwise, this is the ordinal */
271 Ordinal
= OrdinalTable
[Mid
];
273 /* Resolve the address and write it */
274 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
275 ExportDirectory
->AddressOfFunctions
);
276 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
278 /* Check if the function is actually a forwarder */
279 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
280 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
292 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
293 IN PLIST_ENTRY ListHead
)
295 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
296 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
297 PMM_DLL_INITIALIZE DllInit
;
298 UNICODE_STRING RegPath
, ImportName
;
301 /* Try to see if the image exports a DllInitialize routine */
302 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
304 if (!DllInit
) return STATUS_SUCCESS
;
306 /* Do a temporary copy of BaseDllName called ImportName
307 * because we'll alter the length of the string
309 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
310 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
311 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
313 /* Obtain the path to this dll's service in the registry */
314 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
315 ImportName
.Length
+ sizeof(UNICODE_NULL
);
316 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
317 RegPath
.MaximumLength
,
320 /* Check if this allocation was unsuccessful */
321 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
323 /* Build and append the service name itself */
324 RegPath
.Length
= ServicesKeyName
.Length
;
325 RtlCopyMemory(RegPath
.Buffer
,
326 ServicesKeyName
.Buffer
,
327 ServicesKeyName
.Length
);
329 /* Check if there is a dot in the filename */
330 if (wcschr(ImportName
.Buffer
, L
'.'))
332 /* Remove the extension */
333 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
334 ImportName
.Buffer
) * sizeof(WCHAR
);
337 /* Append service name (the basename without extension) */
338 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
340 /* Now call the DllInit func */
341 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
342 Status
= DllInit(&RegPath
);
345 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
347 /* Return status value which DllInitialize returned */
353 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
359 /* Get the unload routine */
360 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
361 if (!Func
) return FALSE
;
363 /* Call it and check for success */
365 if (!NT_SUCCESS(Status
)) return FALSE
;
367 /* Lie about the load count so we can unload the image */
368 ASSERT(LdrEntry
->LoadCount
== 0);
369 LdrEntry
->LoadCount
= 1;
371 /* Unload it and return true */
372 MmUnloadSystemImage(LdrEntry
);
378 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
381 LOAD_IMPORTS SingleEntry
;
382 PLDR_DATA_TABLE_ENTRY LdrEntry
;
383 PVOID CurrentImports
;
386 /* Check if there's no imports or if we're a boot driver */
387 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
388 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
389 (ImportList
->Count
== 0))
391 /* Then there's nothing to do */
392 return STATUS_SUCCESS
;
395 /* Check for single-entry */
396 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
399 SingleEntry
.Count
= 1;
400 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
402 /* Use this as the import list */
403 ImportList
= &SingleEntry
;
406 /* Loop the import list */
407 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
410 LdrEntry
= ImportList
->Entry
[i
];
411 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
413 /* Skip boot loaded images */
414 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
416 /* Dereference the entry */
417 ASSERT(LdrEntry
->LoadCount
>= 1);
418 if (!--LdrEntry
->LoadCount
)
420 /* Save the import data in case unload fails */
421 CurrentImports
= LdrEntry
->LoadedImports
;
423 /* This is the last entry */
424 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
425 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
427 /* Unloading worked, parse this DLL's imports too */
428 MiDereferenceImports(CurrentImports
);
430 /* Check if we had valid imports */
431 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
432 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
433 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
436 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
441 /* Unload failed, restore imports */
442 LdrEntry
->LoadedImports
= CurrentImports
;
448 return STATUS_SUCCESS
;
453 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
457 /* Check if there's no imports or we're a boot driver or only one entry */
458 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
459 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
460 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
466 /* Otherwise, free the import list */
467 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
468 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
473 MiFindExportedRoutineByName(IN PVOID DllBase
,
474 IN PANSI_STRING ExportName
)
477 PUSHORT OrdinalTable
;
478 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
479 LONG Low
= 0, Mid
= 0, High
, Ret
;
486 /* Get the export directory */
487 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
489 IMAGE_DIRECTORY_ENTRY_EXPORT
,
491 if (!ExportDirectory
) return NULL
;
493 /* Setup name tables */
494 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
495 ExportDirectory
->AddressOfNames
);
496 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
497 ExportDirectory
->AddressOfNameOrdinals
);
499 /* Do a binary search */
500 High
= ExportDirectory
->NumberOfNames
- 1;
503 /* Get new middle value */
504 Mid
= (Low
+ High
) >> 1;
507 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
525 /* Check if we couldn't find it */
526 if (High
< Low
) return NULL
;
528 /* Otherwise, this is the ordinal */
529 Ordinal
= OrdinalTable
[Mid
];
531 /* Validate the ordinal */
532 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
534 /* Resolve the address and write it */
535 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
536 ExportDirectory
->AddressOfFunctions
);
537 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
540 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
541 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
547 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
552 /* Acquire module list lock */
553 KeEnterCriticalRegion();
554 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
556 /* Acquire the spinlock too as we will insert or remove the entry */
557 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
559 /* Insert or remove from the list */
560 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
561 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
564 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
565 ExReleaseResourceLite(&PsLoadedModuleResource
);
566 KeLeaveCriticalRegion();
572 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
577 ULONG_PTR OldBaseTop
, Delta
;
578 PLDR_DATA_TABLE_ENTRY LdrEntry
;
579 PLIST_ENTRY NextEntry
;
582 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
583 // since a real version of Windows would fail at this point, but they seem
584 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
585 // a feature which isn't even used by Windows. Priorities, priorities...
586 // Please note that Microsoft WDK EULA and license prohibits using
587 // the information contained within it for the generation of "non-Windows"
588 // drivers, which is precisely what LD will generate, since an LD driver
589 // will not load on Windows.
591 #ifdef _WORKING_LINKER_
594 PULONG_PTR ImageThunk
;
595 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
597 /* Calculate the top and delta */
598 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
599 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
601 /* Loop the loader block */
602 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
603 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
604 NextEntry
= NextEntry
->Flink
)
606 /* Get the loader entry */
607 LdrEntry
= CONTAINING_RECORD(NextEntry
,
608 LDR_DATA_TABLE_ENTRY
,
610 #ifdef _WORKING_LINKER_
612 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
614 IMAGE_DIRECTORY_ENTRY_IAT
,
616 if (!ImageThunk
) continue;
618 /* Make sure we have an IAT */
619 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
620 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
622 /* Check if it's within this module */
623 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
626 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
627 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
628 *ImageThunk
+= Delta
;
632 /* Get the import table */
633 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
635 IMAGE_DIRECTORY_ENTRY_IMPORT
,
637 if (!ImportDescriptor
) continue;
639 /* Make sure we have an IAT */
640 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
641 while ((ImportDescriptor
->Name
) &&
642 (ImportDescriptor
->OriginalFirstThunk
))
644 /* Get the image thunk */
645 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
646 ImportDescriptor
->FirstThunk
);
649 /* Check if it's within this module */
650 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
653 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
654 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
655 *ImageThunk
+= Delta
;
658 /* Go to the next thunk */
662 /* Go to the next import */
671 MiSnapThunk(IN PVOID DllBase
,
673 IN PIMAGE_THUNK_DATA Name
,
674 IN PIMAGE_THUNK_DATA Address
,
675 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
677 IN BOOLEAN SnapForwarder
,
678 OUT PCHAR
*MissingApi
)
683 PUSHORT OrdinalTable
;
684 PIMAGE_IMPORT_BY_NAME NameImport
;
686 ULONG Low
= 0, Mid
= 0, High
;
689 PCHAR MissingForwarder
;
690 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
693 UNICODE_STRING ForwarderName
;
694 PLIST_ENTRY NextEntry
;
695 PLDR_DATA_TABLE_ENTRY LdrEntry
;
696 ULONG ForwardExportSize
;
697 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
698 PIMAGE_IMPORT_BY_NAME ForwardName
;
699 SIZE_T ForwardLength
;
700 IMAGE_THUNK_DATA ForwardThunk
;
703 /* Check if this is an ordinal */
704 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
705 if ((IsOrdinal
) && !(SnapForwarder
))
707 /* Get the ordinal number and set it as missing */
708 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
709 ExportDirectory
->Base
);
710 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
714 /* Get the VA if we don't have to snap */
715 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
716 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
718 /* Copy the procedure name */
719 RtlStringCbCopyA(*MissingApi
,
720 MAXIMUM_FILENAME_LENGTH
,
721 (PCHAR
)&NameImport
->Name
[0]);
723 /* Setup name tables */
724 DPRINT("Import name: %s\n", NameImport
->Name
);
725 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
726 ExportDirectory
->AddressOfNames
);
727 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
728 ExportDirectory
->AddressOfNameOrdinals
);
730 /* Get the hint and check if it's valid */
731 Hint
= NameImport
->Hint
;
732 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
733 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
735 /* We have a match, get the ordinal number from here */
736 Ordinal
= OrdinalTable
[Hint
];
740 /* Do a binary search */
741 High
= ExportDirectory
->NumberOfNames
- 1;
744 /* Get new middle value */
745 Mid
= (Low
+ High
) >> 1;
748 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
766 /* Check if we couldn't find it */
769 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
770 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
773 /* Otherwise, this is the ordinal */
774 Ordinal
= OrdinalTable
[Mid
];
778 /* Check if the ordinal is invalid */
779 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
782 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
786 /* In case the forwarder is missing */
787 MissingForwarder
= NameBuffer
;
789 /* Resolve the address and write it */
790 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
791 ExportDirectory
->AddressOfFunctions
);
792 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
794 /* Assume success from now on */
795 Status
= STATUS_SUCCESS
;
797 /* Check if the function is actually a forwarder */
798 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
799 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
801 /* Now assume failure in case the forwarder doesn't exist */
802 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
804 /* Build the forwarder name */
805 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
806 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
809 DllName
.MaximumLength
= DllName
.Length
;
812 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
816 /* We failed, just return an error */
820 /* Loop the module list */
821 NextEntry
= PsLoadedModuleList
.Flink
;
822 while (NextEntry
!= &PsLoadedModuleList
)
824 /* Get the loader entry */
825 LdrEntry
= CONTAINING_RECORD(NextEntry
,
826 LDR_DATA_TABLE_ENTRY
,
829 /* Check if it matches */
830 if (RtlPrefixString((PSTRING
)&ForwarderName
,
831 (PSTRING
)&LdrEntry
->BaseDllName
,
834 /* Get the forwarder export directory */
835 ForwardExportDirectory
=
836 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
838 IMAGE_DIRECTORY_ENTRY_EXPORT
,
840 if (!ForwardExportDirectory
) break;
842 /* Allocate a name entry */
843 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
845 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
846 sizeof(*ForwardName
) +
849 if (!ForwardName
) break;
852 RtlCopyMemory(&ForwardName
->Name
[0],
853 DllName
.Buffer
+ DllName
.Length
,
855 ForwardName
->Hint
= 0;
857 /* Set the new address */
858 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
860 /* Snap the forwarder */
861 Status
= MiSnapThunk(LdrEntry
->DllBase
,
865 ForwardExportDirectory
,
870 /* Free the forwarder name and set the thunk */
871 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
872 Address
->u1
= ForwardThunk
.u1
;
876 /* Go to the next entry */
877 NextEntry
= NextEntry
->Flink
;
881 RtlFreeUnicodeString(&ForwarderName
);
891 MmUnloadSystemImage(IN PVOID ImageHandle
)
893 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
894 PVOID BaseAddress
= LdrEntry
->DllBase
;
897 BOOLEAN HadEntry
= FALSE
;
899 /* Acquire the loader lock */
900 KeEnterCriticalRegion();
901 KeWaitForSingleObject(&MmSystemLoadLock
,
907 /* Check if this driver was loaded at boot and didn't get imports parsed */
908 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
910 /* We should still be alive */
911 ASSERT(LdrEntry
->LoadCount
!= 0);
912 LdrEntry
->LoadCount
--;
914 /* Check if we're still loaded */
915 if (LdrEntry
->LoadCount
) goto Done
;
917 /* We should cleanup... are symbols loaded */
918 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
920 /* Create the ANSI name */
921 Status
= RtlUnicodeStringToAnsiString(&TempName
,
922 &LdrEntry
->BaseDllName
,
924 if (NT_SUCCESS(Status
))
926 /* Unload the symbols */
927 DbgUnLoadImageSymbols(&TempName
,
929 (ULONG_PTR
)ZwCurrentProcess());
930 RtlFreeAnsiString(&TempName
);
934 /* FIXME: Free the driver */
935 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
936 //MmFreeSection(LdrEntry->DllBase);
938 /* Check if we're linked in */
939 if (LdrEntry
->InLoadOrderLinks
.Flink
)
942 MiProcessLoaderEntry(LdrEntry
, FALSE
);
946 /* Dereference and clear the imports */
947 MiDereferenceImports(LdrEntry
->LoadedImports
);
948 MiClearImports(LdrEntry
);
950 /* Check if the entry needs to go away */
953 /* Check if it had a name */
954 if (LdrEntry
->FullDllName
.Buffer
)
957 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
960 /* Check if we had a section */
961 if (LdrEntry
->SectionPointer
)
964 ObDereferenceObject(LdrEntry
->SectionPointer
);
968 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
971 /* Release the system lock and return */
973 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
974 KeLeaveCriticalRegion();
975 return STATUS_SUCCESS
;
980 MiResolveImageReferences(IN PVOID ImageBase
,
981 IN PUNICODE_STRING ImageFileDirectory
,
982 IN PUNICODE_STRING NamePrefix OPTIONAL
,
983 OUT PCHAR
*MissingApi
,
984 OUT PWCHAR
*MissingDriver
,
985 OUT PLOAD_IMPORTS
*LoadImports
)
987 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
988 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
989 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
990 PLOAD_IMPORTS LoadedImports
, NewImports
;
991 ULONG GdiLink
, NormalLink
, i
;
992 BOOLEAN ReferenceNeeded
, Loaded
;
993 ANSI_STRING TempString
;
994 UNICODE_STRING NameString
, DllName
;
995 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
996 PVOID ImportBase
, DllBase
;
997 PLIST_ENTRY NextEntry
;
998 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1000 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1002 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1003 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1005 /* Assume no imports */
1006 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1008 /* Get the import descriptor */
1009 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1011 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1013 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1015 /* Loop all imports to count them */
1016 for (CurrentImport
= ImportDescriptor
;
1017 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1024 /* Make sure we have non-zero imports */
1027 /* Calculate and allocate the list we'll need */
1028 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1029 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1035 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1036 LoadedImports
->Count
= ImportCount
;
1042 LoadedImports
= NULL
;
1045 /* Reset the import count and loop descriptors again */
1046 ImportCount
= GdiLink
= NormalLink
= 0;
1047 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1050 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1052 /* Check if this is a GDI driver */
1054 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1056 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1057 NormalLink
= NormalLink
|
1058 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1059 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1060 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1061 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1063 /* Check if this is a valid GDI driver */
1064 if ((GdiLink
) && (NormalLink
))
1066 /* It's not, it's importing stuff it shouldn't be! */
1067 MiDereferenceImports(LoadedImports
);
1068 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1069 return STATUS_PROCEDURE_NOT_FOUND
;
1072 /* Check for user-mode printer or video card drivers, which don't belong */
1073 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1074 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1075 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1076 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1077 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1078 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1080 /* This is not kernel code */
1081 MiDereferenceImports(LoadedImports
);
1082 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1083 return STATUS_PROCEDURE_NOT_FOUND
;
1086 /* Check if this is a "core" import, which doesn't get referenced */
1087 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1088 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1089 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1091 /* Don't reference this */
1092 ReferenceNeeded
= FALSE
;
1096 /* Reference these modules */
1097 ReferenceNeeded
= TRUE
;
1100 /* Now setup a unicode string for the import */
1101 RtlInitAnsiString(&TempString
, ImportName
);
1102 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1103 if (!NT_SUCCESS(Status
))
1106 MiDereferenceImports(LoadedImports
);
1107 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1111 /* We don't support name prefixes yet */
1112 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1114 /* Remember that we haven't loaded the import at this point */
1119 /* Loop the driver list */
1120 NextEntry
= PsLoadedModuleList
.Flink
;
1121 while (NextEntry
!= &PsLoadedModuleList
)
1123 /* Get the loader entry and compare the name */
1124 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1125 LDR_DATA_TABLE_ENTRY
,
1127 if (RtlEqualUnicodeString(&NameString
,
1128 &LdrEntry
->BaseDllName
,
1131 /* Get the base address */
1132 ImportBase
= LdrEntry
->DllBase
;
1134 /* Check if we haven't loaded yet, and we need references */
1135 if (!(Loaded
) && (ReferenceNeeded
))
1137 /* Make sure we're not already loading */
1138 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1140 /* Increase the load count */
1141 LdrEntry
->LoadCount
++;
1145 /* Done, break out */
1149 /* Go to the next entry */
1150 NextEntry
= NextEntry
->Flink
;
1153 /* Check if we haven't loaded the import yet */
1156 /* Setup the import DLL name */
1157 DllName
.MaximumLength
= NameString
.Length
+
1158 ImageFileDirectory
->Length
+
1159 sizeof(UNICODE_NULL
);
1160 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1161 DllName
.MaximumLength
,
1165 /* Setup the base length and copy it */
1166 DllName
.Length
= ImageFileDirectory
->Length
;
1167 RtlCopyMemory(DllName
.Buffer
,
1168 ImageFileDirectory
->Buffer
,
1169 ImageFileDirectory
->Length
);
1171 /* Now add the import name and null-terminate it */
1172 RtlAppendUnicodeStringToString(&DllName
,
1174 DllName
.Buffer
[DllName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1176 /* Load the image */
1177 Status
= MmLoadSystemImage(&DllName
,
1183 if (NT_SUCCESS(Status
))
1185 /* We can free the DLL Name */
1186 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1190 /* Fill out the information for the error */
1191 *MissingDriver
= DllName
.Buffer
;
1192 *(PULONG
)MissingDriver
|= 1;
1195 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1200 /* We're out of resources */
1201 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1204 /* Check if we're OK until now */
1205 if (NT_SUCCESS(Status
))
1207 /* We're now loaded */
1211 ASSERT(DllBase
== DllEntry
->DllBase
);
1213 /* Call the initialization routines */
1214 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1215 if (!NT_SUCCESS(Status
))
1217 /* We failed, unload the image */
1218 MmUnloadSystemImage(DllEntry
);
1219 DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status
);
1225 /* Check if we failed by here */
1226 if (!NT_SUCCESS(Status
))
1228 /* Cleanup and return */
1229 RtlFreeUnicodeString(&NameString
);
1230 MiDereferenceImports(LoadedImports
);
1231 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1235 /* Loop again to make sure that everything is OK */
1239 /* Check if we're support to reference this import */
1240 if ((ReferenceNeeded
) && (LoadedImports
))
1242 /* Make sure we're not already loading */
1243 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1246 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1251 /* Free the import name */
1252 RtlFreeUnicodeString(&NameString
);
1254 /* Set the missing driver name and get the export directory */
1255 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1256 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1258 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1260 if (!ExportDirectory
)
1262 /* Cleanup and return */
1263 MiDereferenceImports(LoadedImports
);
1264 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1265 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1266 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1269 /* Make sure we have an IAT */
1270 if (ImportDescriptor
->OriginalFirstThunk
)
1272 /* Get the first thunks */
1273 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1274 ImportDescriptor
->OriginalFirstThunk
);
1275 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1276 ImportDescriptor
->FirstThunk
);
1279 while (OrigThunk
->u1
.AddressOfData
)
1282 Status
= MiSnapThunk(ImportBase
,
1290 if (!NT_SUCCESS(Status
))
1292 /* Cleanup and return */
1293 MiDereferenceImports(LoadedImports
);
1294 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1298 /* Reset the buffer */
1299 *MissingApi
= MissingApiBuffer
;
1303 /* Go to the next import */
1307 /* Check if we have an import list */
1310 /* Reset the count again, and loop entries */
1312 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1314 if (LoadedImports
->Entry
[i
])
1316 /* Got an entry, OR it with 1 in case it's the single entry */
1317 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1318 MM_SYSLDR_SINGLE_ENTRY
);
1323 /* Check if we had no imports */
1326 /* Free the list and set it to no imports */
1327 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1328 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1330 else if (ImportCount
== 1)
1332 /* Just one entry, we can free the table and only use our entry */
1333 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1334 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1336 else if (ImportCount
!= LoadedImports
->Count
)
1338 /* Allocate a new list */
1339 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1340 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1346 NewImports
->Count
= 0;
1348 /* Loop all the imports */
1349 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1351 /* Make sure it's valid */
1352 if (LoadedImports
->Entry
[i
])
1355 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1356 NewImports
->Count
++;
1360 /* Free the old copy */
1361 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1362 LoadedImports
= NewImports
;
1366 /* Return the list */
1367 *LoadImports
= LoadedImports
;
1370 /* Return success */
1371 return STATUS_SUCCESS
;
1376 MiFreeInitializationCode(IN PVOID InitStart
,
1380 PFN_NUMBER PagesFreed
;
1382 /* Get the start PTE */
1383 PointerPte
= MiAddressToPte(InitStart
);
1384 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1386 /* Compute the number of pages we expect to free */
1387 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
+ 1);
1389 /* Try to actually free them */
1390 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1399 MiFindInitializationCode(OUT PVOID
*StartVa
,
1402 ULONG Size
, SectionCount
, Alignment
;
1403 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1404 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1405 PLIST_ENTRY NextEntry
;
1406 PIMAGE_NT_HEADERS NtHeader
;
1407 PIMAGE_SECTION_HEADER Section
, LastSection
;
1410 /* So we don't free our own code yet */
1411 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1413 /* Assume failure */
1416 /* Enter a critical region while we loop the list */
1417 KeEnterCriticalRegion();
1419 /* Loop all loaded modules */
1420 NextEntry
= PsLoadedModuleList
.Flink
;
1421 while (NextEntry
!= &PsLoadedModuleList
)
1423 /* Get the loader entry and its DLL base */
1424 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1425 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1427 /* Get the NT header */
1428 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1432 NextEntry
= NextEntry
->Flink
;
1436 /* Get the first section, the section count, and scan them all */
1437 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1438 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1440 while (SectionCount
> 0)
1442 /* Assume failure */
1445 /* Is this the INIT section or a discardable section? */
1446 if ((*(PULONG
)Section
->Name
== 'TINI') ||
1447 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1455 /* Pick the biggest size -- either raw or virtual */
1456 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1458 /* Read the section alignment */
1459 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1461 /* Align the start and end addresses appropriately */
1462 InitStart
= DllBase
+ Section
->VirtualAddress
;
1463 InitEnd
= ((Alignment
+ InitStart
+ Size
- 2) & 0xFFFFF000) - 1;
1464 InitStart
= (InitStart
+ (PAGE_SIZE
- 1)) & 0xFFFFF000;
1466 /* Have we reached the last section? */
1467 if (SectionCount
== 1)
1470 LastSection
= Section
;
1474 /* We have not, loop all the sections */
1478 /* Keep going until we find a non-discardable section range */
1481 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1483 /* Discardable, so record it, then keep going */
1484 LastSection
= Section
;
1488 /* Non-contigous discard flag, or no flag, break out */
1492 while (SectionCount
> 1);
1495 /* Have we found a discardable or init section? */
1498 /* Pick the biggest size -- either raw or virtual */
1499 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1501 /* Use this as the end of the section address */
1502 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
- 1;
1504 /* Have we reached the last section yet? */
1505 if (SectionCount
!= 1)
1507 /* Then align this accross the session boundary */
1508 InitEnd
= ((Alignment
+ InitEnd
- 1) & 0XFFFFF000) - 1;
1512 /* Make sure we don't let the init section go past the image */
1513 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1514 if (InitEnd
> ImageEnd
) InitEnd
= (ImageEnd
- 1) | (PAGE_SIZE
- 1);
1516 /* Make sure we have a valid, non-zero init section */
1517 if (InitStart
<= InitEnd
)
1519 /* Make sure we are not within this code itself */
1520 if ((InitCode
>= InitStart
) && (InitCode
<= InitEnd
))
1522 /* Return it, we can't free ourselves now */
1523 ASSERT(*StartVa
== 0);
1524 *StartVa
= (PVOID
)InitStart
;
1525 *EndVa
= (PVOID
)InitEnd
;
1529 /* This isn't us -- go ahead and free it */
1530 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1531 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1536 /* Move to the next section */
1541 /* Move to the next module */
1542 NextEntry
= NextEntry
->Flink
;
1545 /* Leave the critical region and return */
1546 KeLeaveCriticalRegion();
1550 * Note: This function assumes that all discardable sections are at the end of
1551 * the PE file. It searches backwards until it finds the non-discardable section
1555 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1557 PMMPTE StartPte
, EndPte
;
1558 PFN_NUMBER PageCount
;
1561 PIMAGE_NT_HEADERS NtHeader
;
1562 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1565 /* Get the base address and the page count */
1566 DllBase
= LdrEntry
->DllBase
;
1567 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1569 /* Get the last PTE in this image */
1570 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1572 /* Get the NT header */
1573 NtHeader
= RtlImageNtHeader(DllBase
);
1574 if (!NtHeader
) return;
1576 /* Get the last section and loop each section backwards */
1577 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1578 DiscardSection
= NULL
;
1579 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1581 /* Go back a section and check if it's discardable */
1583 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1585 /* It is, select it for freeing */
1586 DiscardSection
= Section
;
1590 /* No more discardable sections exist, bail out */
1595 /* Bail out if there's nothing to free */
1596 if (!DiscardSection
) return;
1598 /* Push the DLL base to the first disacrable section, and get its PTE */
1599 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1600 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1601 StartPte
= MiAddressToPte(DllBase
);
1603 /* Check how many pages to free total */
1604 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1605 if (!PageCount
) return;
1607 /* Delete this many PTEs */
1608 PagesDeleted
= MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1614 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1616 PLIST_ENTRY NextEntry
;
1618 PIMAGE_NT_HEADERS NtHeader
;
1619 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1620 PIMAGE_FILE_HEADER FileHeader
;
1621 BOOLEAN ValidRelocs
;
1622 PIMAGE_DATA_DIRECTORY DataDirectory
;
1623 PVOID DllBase
, NewImageAddress
;
1625 PMMPTE PointerPte
, StartPte
, LastPte
;
1628 MMPTE TempPte
, OldPte
;
1630 /* Loop driver list */
1631 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1632 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1633 NextEntry
= NextEntry
->Flink
)
1635 /* Get the loader entry and NT header */
1636 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1637 LDR_DATA_TABLE_ENTRY
,
1639 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1642 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1644 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1645 &LdrEntry
->FullDllName
);
1647 /* Get the first PTE and the number of PTEs we'll need */
1648 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1649 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1650 LastPte
= StartPte
+ PteCount
;
1654 while (PointerPte
< LastPte
)
1657 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1658 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1659 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1660 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1664 /* Skip kernel and HAL */
1665 /* ROS HACK: Skip BOOTVID/KDCOM too */
1667 if (i
<= 4) continue;
1669 /* Skip non-drivers */
1670 if (!NtHeader
) continue;
1672 /* Get the file header and make sure we can relocate */
1673 FileHeader
= &NtHeader
->FileHeader
;
1674 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1675 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1676 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1678 /* Everything made sense until now, check the relocation section too */
1679 DataDirectory
= &NtHeader
->OptionalHeader
.
1680 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1681 if (!DataDirectory
->VirtualAddress
)
1683 /* We don't really have relocations */
1684 ValidRelocs
= FALSE
;
1688 /* Make sure the size is valid */
1689 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1690 LdrEntry
->SizeOfImage
)
1692 /* They're not, skip */
1696 /* We have relocations */
1700 /* Remember the original address */
1701 DllBase
= LdrEntry
->DllBase
;
1704 PointerPte
= StartPte
;
1705 while (PointerPte
< LastPte
)
1707 /* Mark the page modified in the PFN database */
1708 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1709 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1710 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1711 Pfn1
->u3
.e1
.Modified
= TRUE
;
1717 /* Now reserve system PTEs for the image */
1718 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1721 /* Shouldn't happen */
1722 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1726 /* This is the new virtual address for the module */
1727 LastPte
= PointerPte
+ PteCount
;
1728 NewImageAddress
= MiPteToAddress(PointerPte
);
1731 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1732 ASSERT(ExpInitializationPhase
== 0);
1734 /* Loop the new driver PTEs */
1735 TempPte
= ValidKernelPte
;
1736 while (PointerPte
< LastPte
)
1738 /* Copy the old data */
1740 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1742 /* Set page number from the loader's memory */
1743 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1746 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1753 /* Update position */
1754 PointerPte
-= PteCount
;
1757 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1759 /* Set the image base to the address where the loader put it */
1760 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1762 /* Check if we had relocations */
1765 /* Relocate the image */
1766 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1770 STATUS_CONFLICTING_ADDRESSES
,
1771 STATUS_INVALID_IMAGE_FORMAT
);
1772 if (!NT_SUCCESS(Status
))
1774 /* This shouldn't happen */
1775 DPRINT1("Relocations failed!\n");
1780 /* Update the loader entry */
1781 LdrEntry
->DllBase
= NewImageAddress
;
1783 /* Update the thunks */
1784 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1785 MiUpdateThunks(LoaderBlock
,
1788 LdrEntry
->SizeOfImage
);
1790 /* Update the loader entry */
1791 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1792 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1793 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1794 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1796 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1803 MiBuildImportsForBootDrivers(VOID
)
1805 PLIST_ENTRY NextEntry
, NextEntry2
;
1806 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1807 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1808 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1809 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1810 PLOAD_IMPORTS LoadedImports
;
1811 ULONG LoadedImportsSize
, ImportSize
;
1812 PULONG_PTR ImageThunk
;
1813 ULONG_PTR DllBase
, DllEnd
;
1814 ULONG Modules
= 0, i
, j
= 0;
1815 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1817 /* Initialize variables */
1818 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1820 /* Loop the loaded module list... we are early enough that no lock is needed */
1821 NextEntry
= PsLoadedModuleList
.Flink
;
1822 while (NextEntry
!= &PsLoadedModuleList
)
1825 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1826 LDR_DATA_TABLE_ENTRY
,
1829 /* Check if it's the kernel or HAL */
1830 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1833 KernelEntry
= LdrEntry
;
1835 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1838 HalEntry
= LdrEntry
;
1841 /* Check if this is a driver DLL */
1842 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1844 /* Check if this is the HAL or kernel */
1845 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1847 /* Add a reference */
1848 LdrEntry
->LoadCount
= 1;
1852 /* No referencing needed */
1853 LdrEntry
->LoadCount
= 0;
1858 /* No referencing needed */
1859 LdrEntry
->LoadCount
= 0;
1862 /* Remember this came from the loader */
1863 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1866 NextEntry
= NextEntry
->Flink
;
1870 /* We must have at least found the kernel and HAL */
1871 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1873 /* Allocate the list */
1874 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1875 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1877 /* Loop the loaded module list again */
1878 NextEntry
= PsLoadedModuleList
.Flink
;
1879 while (NextEntry
!= &PsLoadedModuleList
)
1882 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1883 LDR_DATA_TABLE_ENTRY
,
1885 #ifdef _WORKING_LOADER_
1886 /* Get its imports */
1887 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1889 IMAGE_DIRECTORY_ENTRY_IAT
,
1893 /* Get its imports */
1894 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1896 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1898 if (!ImportDescriptor
)
1902 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1903 NextEntry
= NextEntry
->Flink
;
1907 /* Clear the list and count the number of IAT thunks */
1908 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1909 #ifdef _WORKING_LOADER_
1910 ImportSize
/= sizeof(ULONG_PTR
);
1912 /* Scan the thunks */
1913 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1915 DllBase
= DllEnd
= i
= 0;
1916 while ((ImportDescriptor
->Name
) &&
1917 (ImportDescriptor
->OriginalFirstThunk
))
1919 /* Get the image thunk */
1920 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1921 ImportDescriptor
->FirstThunk
);
1925 /* Do we already have an address? */
1928 /* Is the thunk in the same address? */
1929 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1931 /* Skip it, we already have a reference for it */
1932 ASSERT(EntryArray
[j
]);
1938 /* Loop the loaded module list to locate this address owner */
1940 NextEntry2
= PsLoadedModuleList
.Flink
;
1941 while (NextEntry2
!= &PsLoadedModuleList
)
1944 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1945 LDR_DATA_TABLE_ENTRY
,
1948 /* Get the address range for this module */
1949 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1950 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1952 /* Check if this IAT entry matches it */
1953 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1956 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1957 EntryArray
[j
] = LdrEntry2
;
1961 /* Keep searching */
1962 NextEntry2
= NextEntry2
->Flink
;
1966 /* Do we have a thunk outside the range? */
1967 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
1972 /* Should not be happening */
1973 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1974 LdrEntry
, ImageThunk
, *ImageThunk
);
1978 /* Reset if we hit this */
1981 #ifndef _WORKING_LOADER_
1990 /* Now scan how many imports we really have */
1991 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
1993 /* Skip HAL and kernel */
1994 if ((EntryArray
[i
]) &&
1995 (EntryArray
[i
] != HalEntry
) &&
1996 (EntryArray
[i
] != KernelEntry
))
1998 /* A valid reference */
1999 LastEntry
= EntryArray
[i
];
2004 /* Do we have any imports after all? */
2008 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2010 else if (ImportSize
== 1)
2012 /* A single entry import */
2013 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2014 LastEntry
->LoadCount
++;
2018 /* We need an import table */
2019 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2020 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2023 ASSERT(LoadedImports
);
2025 /* Save the count */
2026 LoadedImports
->Count
= ImportSize
;
2028 /* Now copy all imports */
2029 for (i
= 0, j
= 0; i
< Modules
; i
++)
2031 /* Skip HAL and kernel */
2032 if ((EntryArray
[i
]) &&
2033 (EntryArray
[i
] != HalEntry
) &&
2034 (EntryArray
[i
] != KernelEntry
))
2036 /* A valid reference */
2037 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2038 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2039 EntryArray
[i
]->LoadCount
++;
2044 /* Should had as many entries as we expected */
2045 ASSERT(j
== ImportSize
);
2046 LdrEntry
->LoadedImports
= LoadedImports
;
2050 NextEntry
= NextEntry
->Flink
;
2053 /* Free the initial array */
2054 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2056 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2058 /* Kernel and HAL are loaded at boot */
2059 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2060 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2062 /* All worked well */
2063 return STATUS_SUCCESS
;
2069 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2072 PIMAGE_NT_HEADERS NtHeaders
;
2073 PIMAGE_SECTION_HEADER SectionHeader
;
2074 ULONG Sections
, Size
;
2076 /* Get the kernel section header */
2077 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2078 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2079 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2081 /* Loop all the sections */
2082 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2085 /* Grab the size of the section */
2086 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2088 /* Check for .RSRC section */
2089 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2091 /* Remember the PTEs so we can modify them later */
2092 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2093 SectionHeader
->VirtualAddress
);
2094 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2095 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2097 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2099 /* POOLCODE vs. POOLMI */
2100 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2102 /* Found Ex* Pool code */
2103 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2104 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2106 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2108 /* Found Mm* Pool code */
2109 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2110 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2113 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2114 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2116 /* Found MISYSPTE (Mm System PTE code)*/
2117 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2118 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2130 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2132 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2133 PLIST_ENTRY ListHead
, NextEntry
;
2136 /* Setup the loaded module list and locks */
2137 ExInitializeResourceLite(&PsLoadedModuleResource
);
2138 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2139 InitializeListHead(&PsLoadedModuleList
);
2141 /* Get loop variables and the kernel entry */
2142 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2143 NextEntry
= ListHead
->Flink
;
2144 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2145 LDR_DATA_TABLE_ENTRY
,
2147 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2149 /* Locate resource section, pool code, and system pte code */
2150 MiLocateKernelSections(LdrEntry
);
2152 /* Loop the loader block */
2153 while (NextEntry
!= ListHead
)
2155 /* Get the loader entry */
2156 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2157 LDR_DATA_TABLE_ENTRY
,
2160 /* FIXME: ROS HACK. Make sure this is a driver */
2161 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2163 /* Skip this entry */
2164 NextEntry
= NextEntry
->Flink
;
2168 /* Calculate the size we'll need and allocate a copy */
2169 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2170 LdrEntry
->BaseDllName
.MaximumLength
+
2171 sizeof(UNICODE_NULL
);
2172 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2173 if (!NewEntry
) return FALSE
;
2175 /* Copy the entry over */
2176 *NewEntry
= *LdrEntry
;
2178 /* Allocate the name */
2179 NewEntry
->FullDllName
.Buffer
=
2180 ExAllocatePoolWithTag(PagedPool
,
2181 LdrEntry
->FullDllName
.MaximumLength
+
2182 sizeof(UNICODE_NULL
),
2184 if (!NewEntry
->FullDllName
.Buffer
)
2186 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2190 /* Set the base name */
2191 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2193 /* Copy the full and base name */
2194 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2195 LdrEntry
->FullDllName
.Buffer
,
2196 LdrEntry
->FullDllName
.MaximumLength
);
2197 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2198 LdrEntry
->BaseDllName
.Buffer
,
2199 LdrEntry
->BaseDllName
.MaximumLength
);
2201 /* Null-terminate the base name */
2202 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2203 sizeof(WCHAR
)] = UNICODE_NULL
;
2205 /* Insert the entry into the list */
2206 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2207 NextEntry
= NextEntry
->Flink
;
2210 /* Build the import lists for the boot drivers */
2211 MiBuildImportsForBootDrivers();
2219 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2220 IN OUT PVOID
*ImageBaseAddress
,
2221 IN PUNICODE_STRING BaseImageName
,
2222 IN BOOLEAN BootDriver
)
2224 PLIST_ENTRY NextEntry
;
2225 BOOLEAN DriverFound
= FALSE
;
2226 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2227 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2228 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2231 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2232 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2235 /* Make sure there's enough system PTEs for a large page driver */
2236 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2241 /* This happens if the registry key had a "*" (wildcard) in it */
2242 if (MiLargePageAllDrivers
== 0)
2244 /* It didn't, so scan the list */
2245 NextEntry
= MiLargePageDriverList
.Flink
;
2246 while (NextEntry
!= &MiLargePageDriverList
)
2248 /* Check if the driver name matches */
2249 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2250 MI_LARGE_PAGE_DRIVER_ENTRY
,
2252 if (RtlEqualUnicodeString(BaseImageName
,
2253 &LargePageDriverEntry
->BaseName
,
2256 /* Enable large pages for this driver */
2262 NextEntry
= NextEntry
->Flink
;
2265 /* If we didn't find the driver, it doesn't need large pages */
2266 if (DriverFound
== FALSE
) return FALSE
;
2269 /* Nothing to do yet */
2270 DPRINT1("Large pages not supported!\n");
2276 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2277 IN ULONG SectionProtection
)
2279 ULONG Protection
= MM_ZERO_ACCESS
;
2281 /* Check if the caller gave anything */
2282 if (SectionProtection
)
2284 /* Always turn on execute access */
2285 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2287 /* Check if the registry setting is on or not */
2288 if (!MmEnforceWriteProtection
)
2290 /* Turn on write access too */
2291 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2295 /* Convert to internal PTE flags */
2296 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2297 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2299 /* Check for write access */
2300 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2302 /* Session space is not supported */
2305 DPRINT1("Session drivers not supported\n");
2306 ASSERT(SessionSpace
== FALSE
);
2310 /* Convert to internal PTE flag */
2311 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2315 /* If there's no access at all by now, convert to internal no access flag */
2316 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2318 /* Return the computed PTE protection */
2324 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2326 IN ULONG ProtectionMask
)
2328 /* I'm afraid to introduce regressions at the moment... */
2334 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2336 PIMAGE_NT_HEADERS NtHeaders
;
2337 PIMAGE_SECTION_HEADER Section
;
2338 PFN_NUMBER DriverPages
;
2339 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2340 ULONG Sections
, Size
;
2341 ULONG_PTR BaseAddress
, CurrentAddress
;
2342 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2343 ULONG CurrentMask
, CombinedMask
= 0;
2346 /* No need to write protect physical memory-backed drivers (large pages) */
2347 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2349 /* Get the image headers */
2350 NtHeaders
= RtlImageNtHeader(ImageBase
);
2351 if (!NtHeaders
) return;
2353 /* Check if this is a session driver or not */
2354 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2356 /* Don't touch NT4 drivers */
2357 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2358 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2363 DPRINT1("Session drivers not supported\n");
2367 /* These are the only protection masks we care about */
2368 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2370 /* Calculate the number of pages this driver is occupying */
2371 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2373 /* Get the number of sections and the first section header */
2374 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2375 ASSERT(Sections
!= 0);
2376 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2378 /* Loop all the sections */
2379 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2382 /* Get the section size */
2383 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2385 /* Get its virtual address */
2386 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2387 if (BaseAddress
< CurrentAddress
)
2389 /* Windows doesn't like these */
2390 DPRINT1("Badly linked image!\n");
2394 /* Remember the current address */
2395 CurrentAddress
= BaseAddress
+ Size
- 1;
2402 /* Get the number of sections and the first section header */
2403 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2404 ASSERT(Sections
!= 0);
2405 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2407 /* Set the address at the end to initialize the loop */
2408 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2409 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2411 /* Set the PTE points for the image, and loop its sections */
2412 StartPte
= MiAddressToPte(ImageBase
);
2413 LastPte
= StartPte
+ DriverPages
;
2416 /* Get the section size */
2417 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2419 /* Get its virtual address and PTE */
2420 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2421 PointerPte
= MiAddressToPte(BaseAddress
);
2423 /* Check if we were already protecting a run, and found a new run */
2424 if ((ComboPte
) && (PointerPte
> ComboPte
))
2426 /* Compute protection */
2427 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2430 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2432 /* Check for overlap */
2433 if (ComboPte
== StartPte
) StartPte
++;
2435 /* One done, reset variables */
2437 CombinedProtection
= 0;
2440 /* Break out when needed */
2441 if (PointerPte
>= LastPte
) break;
2443 /* Get the requested protection from the image header */
2444 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2445 if (SectionProtection
== CurrentProtection
)
2447 /* Same protection, so merge the request */
2448 CurrentAddress
= BaseAddress
+ Size
- 1;
2456 /* This is now a new section, so close up the old one */
2457 CurrentPte
= MiAddressToPte(CurrentAddress
);
2459 /* Check for overlap */
2460 if (CurrentPte
== PointerPte
)
2462 /* Skip the last PTE, since it overlaps with us */
2465 /* And set the PTE we will merge with */
2466 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2467 ComboPte
= PointerPte
;
2469 /* Get the most flexible protection by merging both */
2470 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2473 /* Loop any PTEs left */
2474 if (CurrentPte
>= StartPte
)
2477 ASSERT(StartPte
< LastPte
);
2479 /* Make sure we don't overflow past the last PTE in the driver */
2480 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2481 ASSERT(CurrentPte
>= StartPte
);
2483 /* Compute the protection and set it */
2484 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2485 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2489 StartPte
= PointerPte
;
2490 CurrentAddress
= BaseAddress
+ Size
- 1;
2491 CurrentProtection
= SectionProtection
;
2498 /* Is there a leftover section to merge? */
2501 /* Compute and set the protection */
2502 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2503 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2505 /* Handle overlap */
2506 if (ComboPte
== StartPte
) StartPte
++;
2509 /* Finally, handle the last section */
2510 CurrentPte
= MiAddressToPte(CurrentAddress
);
2511 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2513 /* Handle overlap */
2514 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2515 ASSERT(CurrentPte
>= StartPte
);
2517 /* Compute and set the protection */
2518 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2519 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2525 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2529 PETHREAD CurrentThread
= PsGetCurrentThread();
2530 PFN_COUNT PageCount
= 0;
2531 PFN_NUMBER PageFrameIndex
;
2535 /* Get the driver's base address */
2536 ImageBase
= MiPteToAddress(PointerPte
);
2537 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2539 /* If this is a large page, it's stuck in physical memory */
2540 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2542 /* Lock the working set */
2543 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2546 while (PointerPte
<= LastPte
)
2548 /* Check for valid PTE */
2549 if (PointerPte
->u
.Hard
.Valid
== 1)
2551 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2552 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2553 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2555 /* No working sets in ReactOS yet */
2559 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2563 /* Release the working set */
2564 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2566 /* Do we have any driver pages? */
2569 /* Update counters */
2570 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2576 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2578 ULONG_PTR ImageBase
;
2579 PIMAGE_NT_HEADERS NtHeaders
;
2580 ULONG Sections
, Alignment
, Size
;
2581 PIMAGE_SECTION_HEADER Section
;
2582 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2583 if (MmDisablePagingExecutive
) return;
2585 /* Get the driver base address and its NT header */
2586 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2587 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2588 if (!NtHeaders
) return;
2590 /* Get the sections and their alignment */
2591 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2592 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2594 /* Loop each section */
2595 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2598 /* Find PAGE or .edata */
2599 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2600 (*(PULONG
)Section
->Name
== 'ade.'))
2602 /* Had we already done some work? */
2605 /* Nope, setup the first PTE address */
2606 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2611 /* Compute the size */
2612 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2614 /* Find the last PTE that maps this section */
2615 LastPte
= MiAddressToPte(ImageBase
+
2616 Section
->VirtualAddress
+
2623 /* Had we found a section before? */
2626 /* Mark it as pageable */
2627 MiSetPagingOfDriver(PointerPte
, LastPte
);
2632 /* Keep searching */
2637 /* Handle the straggler */
2638 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2643 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2645 PIMAGE_NT_HEADERS NtHeader
;
2648 /* Get NT Headers */
2649 NtHeader
= RtlImageNtHeader(BaseAddress
);
2652 /* Check if this image is only safe for UP while we have 2+ CPUs */
2653 if ((KeNumberProcessors
> 1) &&
2654 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2661 /* Otherwise, it's safe */
2667 MmCheckSystemImage(IN HANDLE ImageHandle
,
2668 IN BOOLEAN PurgeSection
)
2671 HANDLE SectionHandle
;
2672 PVOID ViewBase
= NULL
;
2673 SIZE_T ViewSize
= 0;
2674 IO_STATUS_BLOCK IoStatusBlock
;
2675 FILE_STANDARD_INFORMATION FileStandardInfo
;
2676 KAPC_STATE ApcState
;
2677 PIMAGE_NT_HEADERS NtHeaders
;
2678 OBJECT_ATTRIBUTES ObjectAttributes
;
2681 /* Setup the object attributes */
2682 InitializeObjectAttributes(&ObjectAttributes
,
2684 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2688 /* Create a section for the DLL */
2689 Status
= ZwCreateSection(&SectionHandle
,
2690 SECTION_MAP_EXECUTE
,
2696 if (!NT_SUCCESS(Status
))
2698 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2702 /* Make sure we're in the system process */
2703 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2706 Status
= ZwMapViewOfSection(SectionHandle
,
2716 if (!NT_SUCCESS(Status
))
2718 /* We failed, close the handle and return */
2719 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2720 KeUnstackDetachProcess(&ApcState
);
2721 ZwClose(SectionHandle
);
2725 /* Now query image information */
2726 Status
= ZwQueryInformationFile(ImageHandle
,
2729 sizeof(FileStandardInfo
),
2730 FileStandardInformation
);
2731 if (NT_SUCCESS(Status
))
2733 /* First, verify the checksum */
2734 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2739 /* Set checksum failure */
2740 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2744 /* Make sure it's a real image */
2745 NtHeaders
= RtlImageNtHeader(ViewBase
);
2748 /* Set checksum failure */
2749 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2753 /* Make sure it's for the correct architecture */
2754 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2755 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2757 /* Set protection failure */
2758 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2762 /* Check that it's a valid SMP image if we have more then one CPU */
2763 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2765 /* Otherwise it's not the right image */
2766 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2770 /* Unmap the section, close the handle, and return status */
2772 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2773 KeUnstackDetachProcess(&ApcState
);
2774 ZwClose(SectionHandle
);
2780 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2781 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2782 IN PUNICODE_STRING LoadedName OPTIONAL
,
2784 OUT PVOID
*ModuleObject
,
2785 OUT PVOID
*ImageBaseAddress
)
2787 PVOID ModuleLoadBase
= NULL
;
2789 HANDLE FileHandle
= NULL
;
2790 OBJECT_ATTRIBUTES ObjectAttributes
;
2791 IO_STATUS_BLOCK IoStatusBlock
;
2792 PIMAGE_NT_HEADERS NtHeader
;
2793 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2794 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2795 ULONG EntrySize
, DriverSize
;
2796 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2797 PCHAR MissingApiName
, Buffer
;
2798 PWCHAR MissingDriverName
;
2799 HANDLE SectionHandle
;
2800 ACCESS_MASK DesiredAccess
;
2801 PVOID Section
= NULL
;
2802 BOOLEAN LockOwned
= FALSE
;
2803 PLIST_ENTRY NextEntry
;
2804 IMAGE_INFO ImageInfo
;
2808 /* Detect session-load */
2812 ASSERT(NamePrefix
== NULL
);
2813 ASSERT(LoadedName
== NULL
);
2815 /* Make sure the process is in session too */
2816 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2819 /* Allocate a buffer we'll use for names */
2820 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2821 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2823 /* Check for a separator */
2824 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2829 /* Loop the path until we get to the base name */
2830 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2831 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2833 /* Get the length */
2834 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2835 BaseLength
*= sizeof(WCHAR
);
2837 /* Setup the string */
2838 BaseName
.Length
= (USHORT
)BaseLength
;
2839 BaseName
.Buffer
= p
;
2843 /* Otherwise, we already have a base name */
2844 BaseName
.Length
= FileName
->Length
;
2845 BaseName
.Buffer
= FileName
->Buffer
;
2848 /* Setup the maximum length */
2849 BaseName
.MaximumLength
= BaseName
.Length
;
2851 /* Now compute the base directory */
2852 BaseDirectory
= *FileName
;
2853 BaseDirectory
.Length
-= BaseName
.Length
;
2854 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2856 /* And the prefix, which for now is just the name itself */
2857 PrefixName
= *FileName
;
2859 /* Check if we have a prefix */
2860 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2862 /* Check if we already have a name, use it instead */
2863 if (LoadedName
) BaseName
= *LoadedName
;
2865 /* Check for loader snap debugging */
2866 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2868 /* Print out standard string */
2869 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2870 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2873 /* Acquire the load lock */
2875 ASSERT(LockOwned
== FALSE
);
2877 KeEnterCriticalRegion();
2878 KeWaitForSingleObject(&MmSystemLoadLock
,
2884 /* Scan the module list */
2885 NextEntry
= PsLoadedModuleList
.Flink
;
2886 while (NextEntry
!= &PsLoadedModuleList
)
2888 /* Get the entry and compare the names */
2889 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2890 LDR_DATA_TABLE_ENTRY
,
2892 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2894 /* Found it, break out */
2899 NextEntry
= NextEntry
->Flink
;
2902 /* Check if we found the image */
2903 if (NextEntry
!= &PsLoadedModuleList
)
2905 /* Check if we had already mapped a section */
2908 /* Dereference and clear */
2909 ObDereferenceObject(Section
);
2913 /* Check if this was supposed to be a session load */
2916 /* It wasn't, so just return the data */
2917 *ModuleObject
= LdrEntry
;
2918 *ImageBaseAddress
= LdrEntry
->DllBase
;
2919 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2923 /* We don't support session loading yet */
2924 DPRINT1("Unsupported Session-Load!\n");
2933 /* It wasn't loaded, and we didn't have a previous attempt */
2934 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2935 KeLeaveCriticalRegion();
2938 /* Check if KD is enabled */
2939 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2941 /* FIXME: Attempt to get image from KD */
2944 /* We don't have a valid entry */
2947 /* Setup image attributes */
2948 InitializeObjectAttributes(&ObjectAttributes
,
2950 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2954 /* Open the image */
2955 Status
= ZwOpenFile(&FileHandle
,
2959 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2961 if (!NT_SUCCESS(Status
))
2963 DPRINT1("ZwOpenFile failed with status 0x%x\n", Status
);
2968 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2969 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2970 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2971 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2977 /* Check if this is a session-load */
2980 /* Then we only need read and execute */
2981 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2985 /* Otherwise, we can allow write access */
2986 DesiredAccess
= SECTION_ALL_ACCESS
;
2989 /* Initialize the attributes for the section */
2990 InitializeObjectAttributes(&ObjectAttributes
,
2992 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2996 /* Create the section */
2997 Status
= ZwCreateSection(&SectionHandle
,
3004 if (!NT_SUCCESS(Status
))
3006 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3010 /* Now get the section pointer */
3011 Status
= ObReferenceObjectByHandle(SectionHandle
,
3012 SECTION_MAP_EXECUTE
,
3013 MmSectionObjectType
,
3017 ZwClose(SectionHandle
);
3018 if (!NT_SUCCESS(Status
)) goto Quickie
;
3020 /* Check if this was supposed to be a session-load */
3023 /* We don't support session loading yet */
3024 DPRINT1("Unsupported Session-Load!\n");
3028 /* Check the loader list again, we should end up in the path below */
3033 /* We don't have a valid entry */
3037 /* Load the image */
3038 Status
= MiLoadImageSection(&Section
,
3043 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3045 /* Get the size of the driver */
3046 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
3048 /* Make sure we're not being loaded into session space */
3051 /* Check for success */
3052 if (NT_SUCCESS(Status
))
3054 /* Support large pages for drivers */
3055 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3061 /* Dereference the section */
3062 ObDereferenceObject(Section
);
3066 /* Check for failure of the load earlier */
3067 if (!NT_SUCCESS(Status
))
3069 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3073 /* Relocate the driver */
3074 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3078 STATUS_CONFLICTING_ADDRESSES
,
3079 STATUS_INVALID_IMAGE_FORMAT
);
3080 if (!NT_SUCCESS(Status
))
3082 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3086 /* Get the NT Header */
3087 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3089 /* Calculate the size we'll need for the entry and allocate it */
3090 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3092 sizeof(UNICODE_NULL
);
3094 /* Allocate the entry */
3095 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3099 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3103 /* Setup the entry */
3104 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3105 LdrEntry
->LoadCount
= 1;
3106 LdrEntry
->LoadedImports
= LoadedImports
;
3107 LdrEntry
->PatchInformation
= NULL
;
3109 /* Check the version */
3110 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3111 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3113 /* Mark this image as a native image */
3114 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3117 /* Setup the rest of the entry */
3118 LdrEntry
->DllBase
= ModuleLoadBase
;
3119 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3120 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3121 LdrEntry
->SizeOfImage
= DriverSize
;
3122 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3123 LdrEntry
->SectionPointer
= Section
;
3125 /* Now write the DLL name */
3126 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3127 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3128 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3130 /* Copy and null-terminate it */
3131 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3134 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3136 /* Now allocate the full name */
3137 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3139 sizeof(UNICODE_NULL
),
3141 if (!LdrEntry
->FullDllName
.Buffer
)
3143 /* Don't fail, just set it to zero */
3144 LdrEntry
->FullDllName
.Length
= 0;
3145 LdrEntry
->FullDllName
.MaximumLength
= 0;
3150 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3151 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3153 /* Copy and null-terminate */
3154 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3157 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3161 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3163 /* Resolve imports */
3164 MissingApiName
= Buffer
;
3165 Status
= MiResolveImageReferences(ModuleLoadBase
,
3171 if (!NT_SUCCESS(Status
))
3173 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3176 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3178 /* Check if we need to free the name */
3179 if (LdrEntry
->FullDllName
.Buffer
)
3182 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3185 /* Free the entry itself */
3186 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3191 /* Update the loader entry */
3192 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3193 LDRP_ENTRY_PROCESSED
|
3195 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3196 LdrEntry
->LoadedImports
= LoadedImports
;
3198 /* FIXME: Call driver verifier's loader function */
3200 /* Write-protect the system image */
3201 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3203 /* Check if notifications are enabled */
3204 if (PsImageNotifyEnabled
)
3206 /* Fill out the notification data */
3207 ImageInfo
.Properties
= 0;
3208 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3209 ImageInfo
.SystemModeImage
= TRUE
;
3210 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3211 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3212 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3214 /* Send the notification */
3215 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3218 #if defined(KDBG) || defined(_WINKD_)
3219 /* MiCacheImageSymbols doesn't detect rossym */
3222 /* Check if there's symbols */
3223 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3226 /* Check if the system root is present */
3227 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3228 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3230 /* Add the system root */
3231 UnicodeTemp
= PrefixName
;
3232 UnicodeTemp
.Buffer
+= 11;
3233 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3236 &SharedUserData
->NtSystemRoot
[2],
3241 /* Build the name */
3242 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3245 /* Setup the ansi string */
3246 RtlInitString(&AnsiTemp
, Buffer
);
3248 /* Notify the debugger */
3249 DbgLoadImageSymbols(&AnsiTemp
,
3251 (ULONG_PTR
)ZwCurrentProcess());
3252 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3255 /* Page the driver */
3256 ASSERT(Section
== NULL
);
3257 MiEnablePagingOfDriver(LdrEntry
);
3259 /* Return pointers */
3260 *ModuleObject
= LdrEntry
;
3261 *ImageBaseAddress
= LdrEntry
->DllBase
;
3264 /* Check if we have the lock acquired */
3267 /* Release the lock */
3268 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3269 KeLeaveCriticalRegion();
3273 /* If we have a file handle, close it */
3274 if (FileHandle
) ZwClose(FileHandle
);
3276 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3277 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3279 /* Free the name buffer and return status */
3280 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3284 PLDR_DATA_TABLE_ENTRY
3286 MiLookupDataTableEntry(IN PVOID Address
)
3288 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3289 PLIST_ENTRY NextEntry
;
3293 NextEntry
= PsLoadedModuleList
.Flink
;
3296 /* Get the loader entry */
3297 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3298 LDR_DATA_TABLE_ENTRY
,
3301 /* Check if the address matches */
3302 if ((Address
>= LdrEntry
->DllBase
) &&
3303 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3304 LdrEntry
->SizeOfImage
)))
3307 FoundEntry
= LdrEntry
;
3312 NextEntry
= NextEntry
->Flink
;
3313 } while(NextEntry
!= &PsLoadedModuleList
);
3315 /* Return the entry */
3319 /* PUBLIC FUNCTIONS ***********************************************************/
3326 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3328 PMMPTE StartPte
, EndPte
;
3329 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3332 /* Get the loader entry */
3333 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3334 if (!LdrEntry
) return NULL
;
3336 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3337 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3339 /* Don't do anything, just return the base address */
3340 return LdrEntry
->DllBase
;
3343 /* Wait for active DPCs to finish before we page out the driver */
3344 KeFlushQueuedDpcs();
3346 /* Get the PTE range for the whole driver image */
3347 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3348 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3350 /* Enable paging for the PTE range */
3351 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3352 MiSetPagingOfDriver(StartPte
, EndPte
);
3354 /* Return the base address */
3355 return LdrEntry
->DllBase
;
3363 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3373 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3375 PVOID ProcAddress
= NULL
;
3376 ANSI_STRING AnsiRoutineName
;
3378 PLIST_ENTRY NextEntry
;
3379 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3380 BOOLEAN Found
= FALSE
;
3381 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3382 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3385 /* Convert routine to ansi name */
3386 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3389 if (!NT_SUCCESS(Status
)) return NULL
;
3392 KeEnterCriticalRegion();
3393 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3395 /* Loop the loaded module list */
3396 NextEntry
= PsLoadedModuleList
.Flink
;
3397 while (NextEntry
!= &PsLoadedModuleList
)
3400 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3401 LDR_DATA_TABLE_ENTRY
,
3404 /* Check if it's the kernel or HAL */
3405 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3411 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3418 /* Check if we found a valid binary */
3421 /* Find the procedure name */
3422 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3425 /* Break out if we found it or if we already tried both modules */
3426 if (ProcAddress
) break;
3427 if (Modules
== 2) break;
3431 NextEntry
= NextEntry
->Flink
;
3434 /* Release the lock */
3435 ExReleaseResourceLite(&PsLoadedModuleResource
);
3436 KeLeaveCriticalRegion();
3438 /* Free the string and return */
3439 RtlFreeAnsiString(&AnsiRoutineName
);