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 UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n");
109 return STATUS_NOT_IMPLEMENTED
;
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
->ImageInformation
.ImageFileSize
) >> 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 */
561 InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
);
563 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
566 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
567 ExReleaseResourceLite(&PsLoadedModuleResource
);
568 KeLeaveCriticalRegion();
574 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
579 ULONG_PTR OldBaseTop
, Delta
;
580 PLDR_DATA_TABLE_ENTRY LdrEntry
;
581 PLIST_ENTRY NextEntry
;
584 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
585 // since a real version of Windows would fail at this point, but they seem
586 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
587 // a feature which isn't even used by Windows. Priorities, priorities...
588 // Please note that Microsoft WDK EULA and license prohibits using
589 // the information contained within it for the generation of "non-Windows"
590 // drivers, which is precisely what LD will generate, since an LD driver
591 // will not load on Windows.
593 #ifdef _WORKING_LINKER_
596 PULONG_PTR ImageThunk
;
597 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
599 /* Calculate the top and delta */
600 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
601 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
603 /* Loop the loader block */
604 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
605 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
606 NextEntry
= NextEntry
->Flink
)
608 /* Get the loader entry */
609 LdrEntry
= CONTAINING_RECORD(NextEntry
,
610 LDR_DATA_TABLE_ENTRY
,
612 #ifdef _WORKING_LINKER_
614 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
616 IMAGE_DIRECTORY_ENTRY_IAT
,
618 if (!ImageThunk
) continue;
620 /* Make sure we have an IAT */
621 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
622 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
624 /* Check if it's within this module */
625 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
628 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
629 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
630 *ImageThunk
+= Delta
;
634 /* Get the import table */
635 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
637 IMAGE_DIRECTORY_ENTRY_IMPORT
,
639 if (!ImportDescriptor
) continue;
641 /* Make sure we have an IAT */
642 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
643 while ((ImportDescriptor
->Name
) &&
644 (ImportDescriptor
->OriginalFirstThunk
))
646 /* Get the image thunk */
647 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
648 ImportDescriptor
->FirstThunk
);
651 /* Check if it's within this module */
652 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
655 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
656 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
657 *ImageThunk
+= Delta
;
660 /* Go to the next thunk */
664 /* Go to the next import */
673 MiSnapThunk(IN PVOID DllBase
,
675 IN PIMAGE_THUNK_DATA Name
,
676 IN PIMAGE_THUNK_DATA Address
,
677 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
679 IN BOOLEAN SnapForwarder
,
680 OUT PCHAR
*MissingApi
)
685 PUSHORT OrdinalTable
;
686 PIMAGE_IMPORT_BY_NAME NameImport
;
688 ULONG Low
= 0, Mid
= 0, High
;
691 PCHAR MissingForwarder
;
692 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
695 UNICODE_STRING ForwarderName
;
696 PLIST_ENTRY NextEntry
;
697 PLDR_DATA_TABLE_ENTRY LdrEntry
;
698 ULONG ForwardExportSize
;
699 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
700 PIMAGE_IMPORT_BY_NAME ForwardName
;
701 SIZE_T ForwardLength
;
702 IMAGE_THUNK_DATA ForwardThunk
;
705 /* Check if this is an ordinal */
706 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
707 if ((IsOrdinal
) && !(SnapForwarder
))
709 /* Get the ordinal number and set it as missing */
710 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
711 ExportDirectory
->Base
);
712 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
716 /* Get the VA if we don't have to snap */
717 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
718 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
720 /* Copy the procedure name */
721 RtlStringCbCopyA(*MissingApi
,
722 MAXIMUM_FILENAME_LENGTH
,
723 (PCHAR
)&NameImport
->Name
[0]);
725 /* Setup name tables */
726 DPRINT("Import name: %s\n", NameImport
->Name
);
727 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
728 ExportDirectory
->AddressOfNames
);
729 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
730 ExportDirectory
->AddressOfNameOrdinals
);
732 /* Get the hint and check if it's valid */
733 Hint
= NameImport
->Hint
;
734 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
735 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
737 /* We have a match, get the ordinal number from here */
738 Ordinal
= OrdinalTable
[Hint
];
742 /* Do a binary search */
743 High
= ExportDirectory
->NumberOfNames
- 1;
746 /* Get new middle value */
747 Mid
= (Low
+ High
) >> 1;
750 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
768 /* Check if we couldn't find it */
771 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
772 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
775 /* Otherwise, this is the ordinal */
776 Ordinal
= OrdinalTable
[Mid
];
780 /* Check if the ordinal is invalid */
781 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
784 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
788 /* In case the forwarder is missing */
789 MissingForwarder
= NameBuffer
;
791 /* Resolve the address and write it */
792 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
793 ExportDirectory
->AddressOfFunctions
);
794 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
796 /* Assume success from now on */
797 Status
= STATUS_SUCCESS
;
799 /* Check if the function is actually a forwarder */
800 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
801 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
803 /* Now assume failure in case the forwarder doesn't exist */
804 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
806 /* Build the forwarder name */
807 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
808 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
811 DllName
.MaximumLength
= DllName
.Length
;
814 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
818 /* We failed, just return an error */
822 /* Loop the module list */
823 NextEntry
= PsLoadedModuleList
.Flink
;
824 while (NextEntry
!= &PsLoadedModuleList
)
826 /* Get the loader entry */
827 LdrEntry
= CONTAINING_RECORD(NextEntry
,
828 LDR_DATA_TABLE_ENTRY
,
831 /* Check if it matches */
832 if (RtlPrefixUnicodeString(&ForwarderName
,
833 &LdrEntry
->BaseDllName
,
836 /* Get the forwarder export directory */
837 ForwardExportDirectory
=
838 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
840 IMAGE_DIRECTORY_ENTRY_EXPORT
,
842 if (!ForwardExportDirectory
) break;
844 /* Allocate a name entry */
845 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
847 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
848 sizeof(*ForwardName
) +
851 if (!ForwardName
) break;
854 RtlCopyMemory(&ForwardName
->Name
[0],
855 DllName
.Buffer
+ DllName
.Length
,
857 ForwardName
->Hint
= 0;
859 /* Set the new address */
860 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
862 /* Snap the forwarder */
863 Status
= MiSnapThunk(LdrEntry
->DllBase
,
867 ForwardExportDirectory
,
872 /* Free the forwarder name and set the thunk */
873 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
874 Address
->u1
= ForwardThunk
.u1
;
878 /* Go to the next entry */
879 NextEntry
= NextEntry
->Flink
;
883 RtlFreeUnicodeString(&ForwarderName
);
893 MmUnloadSystemImage(IN PVOID ImageHandle
)
895 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
896 PVOID BaseAddress
= LdrEntry
->DllBase
;
899 BOOLEAN HadEntry
= FALSE
;
901 /* Acquire the loader lock */
902 KeEnterCriticalRegion();
903 KeWaitForSingleObject(&MmSystemLoadLock
,
909 /* Check if this driver was loaded at boot and didn't get imports parsed */
910 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
912 /* We should still be alive */
913 ASSERT(LdrEntry
->LoadCount
!= 0);
914 LdrEntry
->LoadCount
--;
916 /* Check if we're still loaded */
917 if (LdrEntry
->LoadCount
) goto Done
;
919 /* We should cleanup... are symbols loaded */
920 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
922 /* Create the ANSI name */
923 Status
= RtlUnicodeStringToAnsiString(&TempName
,
924 &LdrEntry
->BaseDllName
,
926 if (NT_SUCCESS(Status
))
928 /* Unload the symbols */
929 DbgUnLoadImageSymbols(&TempName
,
931 (ULONG_PTR
)ZwCurrentProcess());
932 RtlFreeAnsiString(&TempName
);
936 /* FIXME: Free the driver */
937 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
938 //MmFreeSection(LdrEntry->DllBase);
940 /* Check if we're linked in */
941 if (LdrEntry
->InLoadOrderLinks
.Flink
)
944 MiProcessLoaderEntry(LdrEntry
, FALSE
);
948 /* Dereference and clear the imports */
949 MiDereferenceImports(LdrEntry
->LoadedImports
);
950 MiClearImports(LdrEntry
);
952 /* Check if the entry needs to go away */
955 /* Check if it had a name */
956 if (LdrEntry
->FullDllName
.Buffer
)
959 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
962 /* Check if we had a section */
963 if (LdrEntry
->SectionPointer
)
966 ObDereferenceObject(LdrEntry
->SectionPointer
);
970 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
973 /* Release the system lock and return */
975 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
976 KeLeaveCriticalRegion();
977 return STATUS_SUCCESS
;
982 MiResolveImageReferences(IN PVOID ImageBase
,
983 IN PUNICODE_STRING ImageFileDirectory
,
984 IN PUNICODE_STRING NamePrefix OPTIONAL
,
985 OUT PCHAR
*MissingApi
,
986 OUT PWCHAR
*MissingDriver
,
987 OUT PLOAD_IMPORTS
*LoadImports
)
989 static UNICODE_STRING DriversFolderName
= RTL_CONSTANT_STRING(L
"drivers\\");
990 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
991 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
992 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
993 PLOAD_IMPORTS LoadedImports
, NewImports
;
994 ULONG GdiLink
, NormalLink
, i
;
995 BOOLEAN ReferenceNeeded
, Loaded
;
996 ANSI_STRING TempString
;
997 UNICODE_STRING NameString
, DllName
;
998 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
999 PVOID ImportBase
, DllBase
;
1000 PLIST_ENTRY NextEntry
;
1001 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1003 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1005 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1006 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1008 /* No name string buffer yet */
1009 NameString
.Buffer
= NULL
;
1011 /* Assume no imports */
1012 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1014 /* Get the import descriptor */
1015 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1017 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1019 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1021 /* Loop all imports to count them */
1022 for (CurrentImport
= ImportDescriptor
;
1023 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1030 /* Make sure we have non-zero imports */
1033 /* Calculate and allocate the list we'll need */
1034 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1035 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1041 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1042 LoadedImports
->Count
= ImportCount
;
1048 LoadedImports
= NULL
;
1051 /* Reset the import count and loop descriptors again */
1052 ImportCount
= GdiLink
= NormalLink
= 0;
1053 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1056 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1058 /* Check if this is a GDI driver */
1060 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1062 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1063 NormalLink
= NormalLink
|
1064 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1065 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1066 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1067 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1069 /* Check if this is a valid GDI driver */
1070 if ((GdiLink
) && (NormalLink
))
1072 /* It's not, it's importing stuff it shouldn't be! */
1073 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1077 /* Check for user-mode printer or video card drivers, which don't belong */
1078 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1079 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1080 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1081 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1082 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1083 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1085 /* This is not kernel code */
1086 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1090 /* Check if this is a "core" import, which doesn't get referenced */
1091 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1092 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1093 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1095 /* Don't reference this */
1096 ReferenceNeeded
= FALSE
;
1100 /* Reference these modules */
1101 ReferenceNeeded
= TRUE
;
1104 /* Now setup a unicode string for the import */
1105 RtlInitAnsiString(&TempString
, ImportName
);
1106 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1107 if (!NT_SUCCESS(Status
))
1113 /* We don't support name prefixes yet */
1114 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1116 /* Remember that we haven't loaded the import at this point */
1121 /* Loop the driver list */
1122 NextEntry
= PsLoadedModuleList
.Flink
;
1123 while (NextEntry
!= &PsLoadedModuleList
)
1125 /* Get the loader entry and compare the name */
1126 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1127 LDR_DATA_TABLE_ENTRY
,
1129 if (RtlEqualUnicodeString(&NameString
,
1130 &LdrEntry
->BaseDllName
,
1133 /* Get the base address */
1134 ImportBase
= LdrEntry
->DllBase
;
1136 /* Check if we haven't loaded yet, and we need references */
1137 if (!(Loaded
) && (ReferenceNeeded
))
1139 /* Make sure we're not already loading */
1140 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1142 /* Increase the load count */
1143 LdrEntry
->LoadCount
++;
1147 /* Done, break out */
1151 /* Go to the next entry */
1152 NextEntry
= NextEntry
->Flink
;
1155 /* Check if we haven't loaded the import yet */
1158 /* Setup the import DLL name */
1159 DllName
.MaximumLength
= NameString
.Length
+
1160 ImageFileDirectory
->Length
+
1161 sizeof(UNICODE_NULL
);
1162 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1163 DllName
.MaximumLength
,
1165 if (!DllName
.Buffer
)
1167 /* We're out of resources */
1168 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1172 /* Add the import name to the base directory */
1173 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1174 RtlAppendUnicodeStringToString(&DllName
,
1177 /* Load the image */
1178 Status
= MmLoadSystemImage(&DllName
,
1185 /* win32k / GDI drivers can also import from system32 folder */
1186 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) &&
1187 (MI_IS_SESSION_ADDRESS(ImageBase
) || 1)) // HACK
1189 /* Free the old name buffer */
1190 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1192 /* Calculate size for a string the adds 'drivers\' */
1193 DllName
.MaximumLength
+= DriversFolderName
.Length
;
1195 /* Allocate the new buffer */
1196 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1197 DllName
.MaximumLength
,
1199 if (!DllName
.Buffer
)
1201 /* We're out of resources */
1202 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1206 /* Copy image directory and append 'drivers\' folder name */
1207 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1208 RtlAppendUnicodeStringToString(&DllName
, &DriversFolderName
);
1210 /* Now add the import name */
1211 RtlAppendUnicodeStringToString(&DllName
, &NameString
);
1213 /* Try once again to load the image */
1214 Status
= MmLoadSystemImage(&DllName
,
1222 if (!NT_SUCCESS(Status
))
1224 /* Fill out the information for the error */
1225 *MissingDriver
= DllName
.Buffer
;
1226 *(PULONG
)MissingDriver
|= 1;
1229 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1231 /* Don't free the name */
1232 DllName
.Buffer
= NULL
;
1234 /* Cleanup and return */
1238 /* We can free the DLL Name */
1239 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1240 DllName
.Buffer
= NULL
;
1242 /* We're now loaded */
1246 ASSERT(DllBase
== DllEntry
->DllBase
);
1248 /* Call the initialization routines */
1249 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1250 if (!NT_SUCCESS(Status
))
1252 /* We failed, unload the image */
1253 MmUnloadSystemImage(DllEntry
);
1254 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status
);
1258 /* Loop again to make sure that everything is OK */
1262 /* Check if we're support to reference this import */
1263 if ((ReferenceNeeded
) && (LoadedImports
))
1265 /* Make sure we're not already loading */
1266 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1269 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1274 /* Free the import name */
1275 RtlFreeUnicodeString(&NameString
);
1277 /* Set the missing driver name and get the export directory */
1278 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1279 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1281 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1283 if (!ExportDirectory
)
1285 /* Cleanup and return */
1286 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1287 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1291 /* Make sure we have an IAT */
1292 if (ImportDescriptor
->OriginalFirstThunk
)
1294 /* Get the first thunks */
1295 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1296 ImportDescriptor
->OriginalFirstThunk
);
1297 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1298 ImportDescriptor
->FirstThunk
);
1301 while (OrigThunk
->u1
.AddressOfData
)
1304 Status
= MiSnapThunk(ImportBase
,
1312 if (!NT_SUCCESS(Status
))
1314 /* Cleanup and return */
1318 /* Reset the buffer */
1319 *MissingApi
= MissingApiBuffer
;
1323 /* Go to the next import */
1327 /* Check if we have an import list */
1330 /* Reset the count again, and loop entries */
1332 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1334 if (LoadedImports
->Entry
[i
])
1336 /* Got an entry, OR it with 1 in case it's the single entry */
1337 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1338 MM_SYSLDR_SINGLE_ENTRY
);
1343 /* Check if we had no imports */
1346 /* Free the list and set it to no imports */
1347 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1348 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1350 else if (ImportCount
== 1)
1352 /* Just one entry, we can free the table and only use our entry */
1353 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1354 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1356 else if (ImportCount
!= LoadedImports
->Count
)
1358 /* Allocate a new list */
1359 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1360 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1366 NewImports
->Count
= 0;
1368 /* Loop all the imports */
1369 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1371 /* Make sure it's valid */
1372 if (LoadedImports
->Entry
[i
])
1375 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1376 NewImports
->Count
++;
1380 /* Free the old copy */
1381 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1382 LoadedImports
= NewImports
;
1386 /* Return the list */
1387 *LoadImports
= LoadedImports
;
1390 /* Return success */
1391 return STATUS_SUCCESS
;
1395 /* Cleanup and return */
1396 RtlFreeUnicodeString(&NameString
);
1400 MiDereferenceImports(LoadedImports
);
1401 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1409 MiFreeInitializationCode(IN PVOID InitStart
,
1413 PFN_NUMBER PagesFreed
;
1415 /* Get the start PTE */
1416 PointerPte
= MiAddressToPte(InitStart
);
1417 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1419 /* Compute the number of pages we expect to free */
1420 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
+ 1);
1422 /* Try to actually free them */
1423 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1432 MiFindInitializationCode(OUT PVOID
*StartVa
,
1435 ULONG Size
, SectionCount
, Alignment
;
1436 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1437 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1438 PLIST_ENTRY NextEntry
;
1439 PIMAGE_NT_HEADERS NtHeader
;
1440 PIMAGE_SECTION_HEADER Section
, LastSection
;
1443 /* So we don't free our own code yet */
1444 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1446 /* Assume failure */
1449 /* Enter a critical region while we loop the list */
1450 KeEnterCriticalRegion();
1452 /* Loop all loaded modules */
1453 NextEntry
= PsLoadedModuleList
.Flink
;
1454 while (NextEntry
!= &PsLoadedModuleList
)
1456 /* Get the loader entry and its DLL base */
1457 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1458 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1460 /* Get the NT header */
1461 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1465 NextEntry
= NextEntry
->Flink
;
1469 /* Get the first section, the section count, and scan them all */
1470 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1471 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1473 while (SectionCount
> 0)
1475 /* Assume failure */
1478 /* Is this the INIT section or a discardable section? */
1479 if ((*(PULONG
)Section
->Name
== 'TINI') ||
1480 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1488 /* Pick the biggest size -- either raw or virtual */
1489 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1491 /* Read the section alignment */
1492 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1494 /* Align the start and end addresses appropriately */
1495 InitStart
= DllBase
+ Section
->VirtualAddress
;
1496 InitEnd
= ((Alignment
+ InitStart
+ Size
- 2) & 0xFFFFF000) - 1;
1497 InitStart
= (InitStart
+ (PAGE_SIZE
- 1)) & 0xFFFFF000;
1499 /* Have we reached the last section? */
1500 if (SectionCount
== 1)
1503 LastSection
= Section
;
1507 /* We have not, loop all the sections */
1511 /* Keep going until we find a non-discardable section range */
1514 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1516 /* Discardable, so record it, then keep going */
1517 LastSection
= Section
;
1521 /* Non-contigous discard flag, or no flag, break out */
1525 while (SectionCount
> 1);
1528 /* Have we found a discardable or init section? */
1531 /* Pick the biggest size -- either raw or virtual */
1532 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1534 /* Use this as the end of the section address */
1535 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
- 1;
1537 /* Have we reached the last section yet? */
1538 if (SectionCount
!= 1)
1540 /* Then align this accross the session boundary */
1541 InitEnd
= ((Alignment
+ InitEnd
- 1) & 0XFFFFF000) - 1;
1545 /* Make sure we don't let the init section go past the image */
1546 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1547 if (InitEnd
> ImageEnd
) InitEnd
= (ImageEnd
- 1) | (PAGE_SIZE
- 1);
1549 /* Make sure we have a valid, non-zero init section */
1550 if (InitStart
<= InitEnd
)
1552 /* Make sure we are not within this code itself */
1553 if ((InitCode
>= InitStart
) && (InitCode
<= InitEnd
))
1555 /* Return it, we can't free ourselves now */
1556 ASSERT(*StartVa
== 0);
1557 *StartVa
= (PVOID
)InitStart
;
1558 *EndVa
= (PVOID
)InitEnd
;
1562 /* This isn't us -- go ahead and free it */
1563 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1564 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1569 /* Move to the next section */
1574 /* Move to the next module */
1575 NextEntry
= NextEntry
->Flink
;
1578 /* Leave the critical region and return */
1579 KeLeaveCriticalRegion();
1583 * Note: This function assumes that all discardable sections are at the end of
1584 * the PE file. It searches backwards until it finds the non-discardable section
1588 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1590 PMMPTE StartPte
, EndPte
;
1591 PFN_NUMBER PageCount
;
1594 PIMAGE_NT_HEADERS NtHeader
;
1595 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1597 /* Get the base address and the page count */
1598 DllBase
= LdrEntry
->DllBase
;
1599 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1601 /* Get the last PTE in this image */
1602 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1604 /* Get the NT header */
1605 NtHeader
= RtlImageNtHeader(DllBase
);
1606 if (!NtHeader
) return;
1608 /* Get the last section and loop each section backwards */
1609 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1610 DiscardSection
= NULL
;
1611 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1613 /* Go back a section and check if it's discardable */
1615 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1617 /* It is, select it for freeing */
1618 DiscardSection
= Section
;
1622 /* No more discardable sections exist, bail out */
1627 /* Bail out if there's nothing to free */
1628 if (!DiscardSection
) return;
1630 /* Push the DLL base to the first disacrable section, and get its PTE */
1631 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1632 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1633 StartPte
= MiAddressToPte(DllBase
);
1635 /* Check how many pages to free total */
1636 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1637 if (!PageCount
) return;
1639 /* Delete this many PTEs */
1640 MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1646 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1648 PLIST_ENTRY NextEntry
;
1650 PIMAGE_NT_HEADERS NtHeader
;
1651 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1652 PIMAGE_FILE_HEADER FileHeader
;
1653 BOOLEAN ValidRelocs
;
1654 PIMAGE_DATA_DIRECTORY DataDirectory
;
1655 PVOID DllBase
, NewImageAddress
;
1657 PMMPTE PointerPte
, StartPte
, LastPte
;
1660 MMPTE TempPte
, OldPte
;
1662 /* Loop driver list */
1663 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1664 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1665 NextEntry
= NextEntry
->Flink
)
1667 /* Get the loader entry and NT header */
1668 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1669 LDR_DATA_TABLE_ENTRY
,
1671 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1674 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1676 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1677 &LdrEntry
->FullDllName
);
1679 /* Get the first PTE and the number of PTEs we'll need */
1680 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1681 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1682 LastPte
= StartPte
+ PteCount
;
1686 while (PointerPte
< LastPte
)
1689 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1690 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1691 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1692 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1696 /* Skip kernel and HAL */
1697 /* ROS HACK: Skip BOOTVID/KDCOM too */
1699 if (i
<= 4) continue;
1701 /* Skip non-drivers */
1702 if (!NtHeader
) continue;
1704 /* Get the file header and make sure we can relocate */
1705 FileHeader
= &NtHeader
->FileHeader
;
1706 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1707 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1708 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1710 /* Everything made sense until now, check the relocation section too */
1711 DataDirectory
= &NtHeader
->OptionalHeader
.
1712 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1713 if (!DataDirectory
->VirtualAddress
)
1715 /* We don't really have relocations */
1716 ValidRelocs
= FALSE
;
1720 /* Make sure the size is valid */
1721 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1722 LdrEntry
->SizeOfImage
)
1724 /* They're not, skip */
1728 /* We have relocations */
1732 /* Remember the original address */
1733 DllBase
= LdrEntry
->DllBase
;
1736 PointerPte
= StartPte
;
1737 while (PointerPte
< LastPte
)
1739 /* Mark the page modified in the PFN database */
1740 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1741 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1742 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1743 Pfn1
->u3
.e1
.Modified
= TRUE
;
1749 /* Now reserve system PTEs for the image */
1750 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1753 /* Shouldn't happen */
1754 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1758 /* This is the new virtual address for the module */
1759 LastPte
= PointerPte
+ PteCount
;
1760 NewImageAddress
= MiPteToAddress(PointerPte
);
1763 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1764 ASSERT(ExpInitializationPhase
== 0);
1766 /* Loop the new driver PTEs */
1767 TempPte
= ValidKernelPte
;
1768 while (PointerPte
< LastPte
)
1770 /* Copy the old data */
1772 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1774 /* Set page number from the loader's memory */
1775 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1778 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1785 /* Update position */
1786 PointerPte
-= PteCount
;
1789 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1791 /* Set the image base to the address where the loader put it */
1792 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1794 /* Check if we had relocations */
1797 /* Relocate the image */
1798 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1802 STATUS_CONFLICTING_ADDRESSES
,
1803 STATUS_INVALID_IMAGE_FORMAT
);
1804 if (!NT_SUCCESS(Status
))
1806 /* This shouldn't happen */
1807 ERROR_FATAL("Relocations failed!\n");
1812 /* Update the loader entry */
1813 LdrEntry
->DllBase
= NewImageAddress
;
1815 /* Update the thunks */
1816 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1817 MiUpdateThunks(LoaderBlock
,
1820 LdrEntry
->SizeOfImage
);
1822 /* Update the loader entry */
1823 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1824 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1825 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1826 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1828 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1835 MiBuildImportsForBootDrivers(VOID
)
1837 PLIST_ENTRY NextEntry
, NextEntry2
;
1838 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1839 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1840 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1841 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1842 PLOAD_IMPORTS LoadedImports
;
1843 ULONG LoadedImportsSize
, ImportSize
;
1844 PULONG_PTR ImageThunk
;
1845 ULONG_PTR DllBase
, DllEnd
;
1846 ULONG Modules
= 0, i
, j
= 0;
1847 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1849 /* Initialize variables */
1850 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1852 /* Loop the loaded module list... we are early enough that no lock is needed */
1853 NextEntry
= PsLoadedModuleList
.Flink
;
1854 while (NextEntry
!= &PsLoadedModuleList
)
1857 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1858 LDR_DATA_TABLE_ENTRY
,
1861 /* Check if it's the kernel or HAL */
1862 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1865 KernelEntry
= LdrEntry
;
1867 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1870 HalEntry
= LdrEntry
;
1873 /* Check if this is a driver DLL */
1874 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1876 /* Check if this is the HAL or kernel */
1877 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1879 /* Add a reference */
1880 LdrEntry
->LoadCount
= 1;
1884 /* No referencing needed */
1885 LdrEntry
->LoadCount
= 0;
1890 /* No referencing needed */
1891 LdrEntry
->LoadCount
= 0;
1894 /* Remember this came from the loader */
1895 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1898 NextEntry
= NextEntry
->Flink
;
1902 /* We must have at least found the kernel and HAL */
1903 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1905 /* Allocate the list */
1906 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1907 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1909 /* Loop the loaded module list again */
1910 NextEntry
= PsLoadedModuleList
.Flink
;
1911 while (NextEntry
!= &PsLoadedModuleList
)
1914 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1915 LDR_DATA_TABLE_ENTRY
,
1917 #ifdef _WORKING_LOADER_
1918 /* Get its imports */
1919 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1921 IMAGE_DIRECTORY_ENTRY_IAT
,
1925 /* Get its imports */
1926 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1928 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1930 if (!ImportDescriptor
)
1934 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1935 NextEntry
= NextEntry
->Flink
;
1939 /* Clear the list and count the number of IAT thunks */
1940 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1941 #ifdef _WORKING_LOADER_
1942 ImportSize
/= sizeof(ULONG_PTR
);
1944 /* Scan the thunks */
1945 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1947 DllBase
= DllEnd
= i
= 0;
1948 while ((ImportDescriptor
->Name
) &&
1949 (ImportDescriptor
->OriginalFirstThunk
))
1951 /* Get the image thunk */
1952 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1953 ImportDescriptor
->FirstThunk
);
1957 /* Do we already have an address? */
1960 /* Is the thunk in the same address? */
1961 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1963 /* Skip it, we already have a reference for it */
1964 ASSERT(EntryArray
[j
]);
1970 /* Loop the loaded module list to locate this address owner */
1972 NextEntry2
= PsLoadedModuleList
.Flink
;
1973 while (NextEntry2
!= &PsLoadedModuleList
)
1976 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
1977 LDR_DATA_TABLE_ENTRY
,
1980 /* Get the address range for this module */
1981 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
1982 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
1984 /* Check if this IAT entry matches it */
1985 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1988 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1989 EntryArray
[j
] = LdrEntry2
;
1993 /* Keep searching */
1994 NextEntry2
= NextEntry2
->Flink
;
1998 /* Do we have a thunk outside the range? */
1999 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
2004 /* Should not be happening */
2005 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2006 LdrEntry
, ImageThunk
, *ImageThunk
);
2009 /* Reset if we hit this */
2012 #ifndef _WORKING_LOADER_
2021 /* Now scan how many imports we really have */
2022 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
2024 /* Skip HAL and kernel */
2025 if ((EntryArray
[i
]) &&
2026 (EntryArray
[i
] != HalEntry
) &&
2027 (EntryArray
[i
] != KernelEntry
))
2029 /* A valid reference */
2030 LastEntry
= EntryArray
[i
];
2035 /* Do we have any imports after all? */
2039 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2041 else if (ImportSize
== 1)
2043 /* A single entry import */
2044 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2045 LastEntry
->LoadCount
++;
2049 /* We need an import table */
2050 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2051 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2054 ASSERT(LoadedImports
);
2056 /* Save the count */
2057 LoadedImports
->Count
= ImportSize
;
2059 /* Now copy all imports */
2060 for (i
= 0, j
= 0; i
< Modules
; i
++)
2062 /* Skip HAL and kernel */
2063 if ((EntryArray
[i
]) &&
2064 (EntryArray
[i
] != HalEntry
) &&
2065 (EntryArray
[i
] != KernelEntry
))
2067 /* A valid reference */
2068 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2069 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2070 EntryArray
[i
]->LoadCount
++;
2075 /* Should had as many entries as we expected */
2076 ASSERT(j
== ImportSize
);
2077 LdrEntry
->LoadedImports
= LoadedImports
;
2081 NextEntry
= NextEntry
->Flink
;
2084 /* Free the initial array */
2085 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2087 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2089 /* Kernel and HAL are loaded at boot */
2090 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2091 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2093 /* All worked well */
2094 return STATUS_SUCCESS
;
2100 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2103 PIMAGE_NT_HEADERS NtHeaders
;
2104 PIMAGE_SECTION_HEADER SectionHeader
;
2105 ULONG Sections
, Size
;
2107 /* Get the kernel section header */
2108 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2109 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2110 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2112 /* Loop all the sections */
2113 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2116 /* Grab the size of the section */
2117 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2119 /* Check for .RSRC section */
2120 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2122 /* Remember the PTEs so we can modify them later */
2123 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2124 SectionHeader
->VirtualAddress
);
2125 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2126 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2128 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2130 /* POOLCODE vs. POOLMI */
2131 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2133 /* Found Ex* Pool code */
2134 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2135 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2137 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2139 /* Found Mm* Pool code */
2140 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2141 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2144 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2145 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2147 /* Found MISYSPTE (Mm System PTE code)*/
2148 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2149 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2161 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2163 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2164 PLIST_ENTRY ListHead
, NextEntry
;
2167 /* Setup the loaded module list and locks */
2168 ExInitializeResourceLite(&PsLoadedModuleResource
);
2169 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2170 InitializeListHead(&PsLoadedModuleList
);
2172 /* Get loop variables and the kernel entry */
2173 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2174 NextEntry
= ListHead
->Flink
;
2175 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2176 LDR_DATA_TABLE_ENTRY
,
2178 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2180 /* Locate resource section, pool code, and system pte code */
2181 MiLocateKernelSections(LdrEntry
);
2183 /* Loop the loader block */
2184 while (NextEntry
!= ListHead
)
2186 /* Get the loader entry */
2187 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2188 LDR_DATA_TABLE_ENTRY
,
2191 /* FIXME: ROS HACK. Make sure this is a driver */
2192 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2194 /* Skip this entry */
2195 NextEntry
= NextEntry
->Flink
;
2199 /* Calculate the size we'll need and allocate a copy */
2200 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2201 LdrEntry
->BaseDllName
.MaximumLength
+
2202 sizeof(UNICODE_NULL
);
2203 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2204 if (!NewEntry
) return FALSE
;
2206 /* Copy the entry over */
2207 *NewEntry
= *LdrEntry
;
2209 /* Allocate the name */
2210 NewEntry
->FullDllName
.Buffer
=
2211 ExAllocatePoolWithTag(PagedPool
,
2212 LdrEntry
->FullDllName
.MaximumLength
+
2213 sizeof(UNICODE_NULL
),
2215 if (!NewEntry
->FullDllName
.Buffer
)
2217 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2221 /* Set the base name */
2222 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2224 /* Copy the full and base name */
2225 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2226 LdrEntry
->FullDllName
.Buffer
,
2227 LdrEntry
->FullDllName
.MaximumLength
);
2228 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2229 LdrEntry
->BaseDllName
.Buffer
,
2230 LdrEntry
->BaseDllName
.MaximumLength
);
2232 /* Null-terminate the base name */
2233 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2234 sizeof(WCHAR
)] = UNICODE_NULL
;
2236 /* Insert the entry into the list */
2237 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2238 NextEntry
= NextEntry
->Flink
;
2241 /* Build the import lists for the boot drivers */
2242 MiBuildImportsForBootDrivers();
2250 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2251 IN OUT PVOID
*ImageBaseAddress
,
2252 IN PUNICODE_STRING BaseImageName
,
2253 IN BOOLEAN BootDriver
)
2255 PLIST_ENTRY NextEntry
;
2256 BOOLEAN DriverFound
= FALSE
;
2257 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2258 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2259 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2262 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2263 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2266 /* Make sure there's enough system PTEs for a large page driver */
2267 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2272 /* This happens if the registry key had a "*" (wildcard) in it */
2273 if (MiLargePageAllDrivers
== 0)
2275 /* It didn't, so scan the list */
2276 NextEntry
= MiLargePageDriverList
.Flink
;
2277 while (NextEntry
!= &MiLargePageDriverList
)
2279 /* Check if the driver name matches */
2280 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2281 MI_LARGE_PAGE_DRIVER_ENTRY
,
2283 if (RtlEqualUnicodeString(BaseImageName
,
2284 &LargePageDriverEntry
->BaseName
,
2287 /* Enable large pages for this driver */
2293 NextEntry
= NextEntry
->Flink
;
2296 /* If we didn't find the driver, it doesn't need large pages */
2297 if (DriverFound
== FALSE
) return FALSE
;
2300 /* Nothing to do yet */
2301 DPRINT1("Large pages not supported!\n");
2307 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2308 IN ULONG SectionProtection
)
2310 ULONG Protection
= MM_ZERO_ACCESS
;
2312 /* Check if the caller gave anything */
2313 if (SectionProtection
)
2315 /* Always turn on execute access */
2316 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2318 /* Check if the registry setting is on or not */
2319 if (!MmEnforceWriteProtection
)
2321 /* Turn on write access too */
2322 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2326 /* Convert to internal PTE flags */
2327 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2328 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2330 /* Check for write access */
2331 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2333 /* Session space is not supported */
2336 DPRINT1("Session drivers not supported\n");
2337 ASSERT(SessionSpace
== FALSE
);
2341 /* Convert to internal PTE flag */
2342 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2346 /* If there's no access at all by now, convert to internal no access flag */
2347 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2349 /* Return the computed PTE protection */
2355 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2357 IN ULONG ProtectionMask
)
2359 /* I'm afraid to introduce regressions at the moment... */
2365 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2367 PIMAGE_NT_HEADERS NtHeaders
;
2368 PIMAGE_SECTION_HEADER Section
;
2369 PFN_NUMBER DriverPages
;
2370 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2371 ULONG Sections
, Size
;
2372 ULONG_PTR BaseAddress
, CurrentAddress
;
2373 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2374 ULONG CurrentMask
, CombinedMask
= 0;
2377 /* No need to write protect physical memory-backed drivers (large pages) */
2378 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2380 /* Get the image headers */
2381 NtHeaders
= RtlImageNtHeader(ImageBase
);
2382 if (!NtHeaders
) return;
2384 /* Check if this is a session driver or not */
2385 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2387 /* Don't touch NT4 drivers */
2388 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2389 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2394 UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n");
2397 /* These are the only protection masks we care about */
2398 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2400 /* Calculate the number of pages this driver is occupying */
2401 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2403 /* Get the number of sections and the first section header */
2404 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2405 ASSERT(Sections
!= 0);
2406 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2408 /* Loop all the sections */
2409 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2412 /* Get the section size */
2413 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2415 /* Get its virtual address */
2416 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2417 if (BaseAddress
< CurrentAddress
)
2419 /* Windows doesn't like these */
2420 DPRINT1("Badly linked image!\n");
2424 /* Remember the current address */
2425 CurrentAddress
= BaseAddress
+ Size
- 1;
2432 /* Get the number of sections and the first section header */
2433 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2434 ASSERT(Sections
!= 0);
2435 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2437 /* Set the address at the end to initialize the loop */
2438 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2439 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2441 /* Set the PTE points for the image, and loop its sections */
2442 StartPte
= MiAddressToPte(ImageBase
);
2443 LastPte
= StartPte
+ DriverPages
;
2446 /* Get the section size */
2447 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2449 /* Get its virtual address and PTE */
2450 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2451 PointerPte
= MiAddressToPte(BaseAddress
);
2453 /* Check if we were already protecting a run, and found a new run */
2454 if ((ComboPte
) && (PointerPte
> ComboPte
))
2456 /* Compute protection */
2457 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2460 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2462 /* Check for overlap */
2463 if (ComboPte
== StartPte
) StartPte
++;
2465 /* One done, reset variables */
2467 CombinedProtection
= 0;
2470 /* Break out when needed */
2471 if (PointerPte
>= LastPte
) break;
2473 /* Get the requested protection from the image header */
2474 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2475 if (SectionProtection
== CurrentProtection
)
2477 /* Same protection, so merge the request */
2478 CurrentAddress
= BaseAddress
+ Size
- 1;
2486 /* This is now a new section, so close up the old one */
2487 CurrentPte
= MiAddressToPte(CurrentAddress
);
2489 /* Check for overlap */
2490 if (CurrentPte
== PointerPte
)
2492 /* Skip the last PTE, since it overlaps with us */
2495 /* And set the PTE we will merge with */
2496 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2497 ComboPte
= PointerPte
;
2499 /* Get the most flexible protection by merging both */
2500 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2503 /* Loop any PTEs left */
2504 if (CurrentPte
>= StartPte
)
2507 ASSERT(StartPte
< LastPte
);
2509 /* Make sure we don't overflow past the last PTE in the driver */
2510 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2511 ASSERT(CurrentPte
>= StartPte
);
2513 /* Compute the protection and set it */
2514 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2515 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2519 StartPte
= PointerPte
;
2520 CurrentAddress
= BaseAddress
+ Size
- 1;
2521 CurrentProtection
= SectionProtection
;
2528 /* Is there a leftover section to merge? */
2531 /* Compute and set the protection */
2532 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2533 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2535 /* Handle overlap */
2536 if (ComboPte
== StartPte
) StartPte
++;
2539 /* Finally, handle the last section */
2540 CurrentPte
= MiAddressToPte(CurrentAddress
);
2541 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2543 /* Handle overlap */
2544 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2545 ASSERT(CurrentPte
>= StartPte
);
2547 /* Compute and set the protection */
2548 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2549 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2555 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2559 PETHREAD CurrentThread
= PsGetCurrentThread();
2560 PFN_COUNT PageCount
= 0;
2561 PFN_NUMBER PageFrameIndex
;
2565 /* Get the driver's base address */
2566 ImageBase
= MiPteToAddress(PointerPte
);
2567 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2569 /* If this is a large page, it's stuck in physical memory */
2570 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2572 /* Lock the working set */
2573 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2576 while (PointerPte
<= LastPte
)
2578 /* Check for valid PTE */
2579 if (PointerPte
->u
.Hard
.Valid
== 1)
2581 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2582 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2583 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2585 /* No working sets in ReactOS yet */
2589 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2593 /* Release the working set */
2594 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2596 /* Do we have any driver pages? */
2599 /* Update counters */
2600 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2606 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2608 ULONG_PTR ImageBase
;
2609 PIMAGE_NT_HEADERS NtHeaders
;
2610 ULONG Sections
, Alignment
, Size
;
2611 PIMAGE_SECTION_HEADER Section
;
2612 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2613 if (MmDisablePagingExecutive
) return;
2615 /* Get the driver base address and its NT header */
2616 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2617 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2618 if (!NtHeaders
) return;
2620 /* Get the sections and their alignment */
2621 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2622 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2624 /* Loop each section */
2625 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2628 /* Find PAGE or .edata */
2629 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2630 (*(PULONG
)Section
->Name
== 'ade.'))
2632 /* Had we already done some work? */
2635 /* Nope, setup the first PTE address */
2636 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2641 /* Compute the size */
2642 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2644 /* Find the last PTE that maps this section */
2645 LastPte
= MiAddressToPte(ImageBase
+
2646 Section
->VirtualAddress
+
2653 /* Had we found a section before? */
2656 /* Mark it as pageable */
2657 MiSetPagingOfDriver(PointerPte
, LastPte
);
2662 /* Keep searching */
2667 /* Handle the straggler */
2668 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2673 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2675 PIMAGE_NT_HEADERS NtHeader
;
2678 /* Get NT Headers */
2679 NtHeader
= RtlImageNtHeader(BaseAddress
);
2682 /* Check if this image is only safe for UP while we have 2+ CPUs */
2683 if ((KeNumberProcessors
> 1) &&
2684 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2691 /* Otherwise, it's safe */
2697 MmCheckSystemImage(IN HANDLE ImageHandle
,
2698 IN BOOLEAN PurgeSection
)
2701 HANDLE SectionHandle
;
2702 PVOID ViewBase
= NULL
;
2703 SIZE_T ViewSize
= 0;
2704 IO_STATUS_BLOCK IoStatusBlock
;
2705 FILE_STANDARD_INFORMATION FileStandardInfo
;
2706 KAPC_STATE ApcState
;
2707 PIMAGE_NT_HEADERS NtHeaders
;
2708 OBJECT_ATTRIBUTES ObjectAttributes
;
2711 /* Setup the object attributes */
2712 InitializeObjectAttributes(&ObjectAttributes
,
2714 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2718 /* Create a section for the DLL */
2719 Status
= ZwCreateSection(&SectionHandle
,
2720 SECTION_MAP_EXECUTE
,
2726 if (!NT_SUCCESS(Status
))
2728 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2732 /* Make sure we're in the system process */
2733 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2736 Status
= ZwMapViewOfSection(SectionHandle
,
2746 if (!NT_SUCCESS(Status
))
2748 /* We failed, close the handle and return */
2749 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2750 KeUnstackDetachProcess(&ApcState
);
2751 ZwClose(SectionHandle
);
2755 /* Now query image information */
2756 Status
= ZwQueryInformationFile(ImageHandle
,
2759 sizeof(FileStandardInfo
),
2760 FileStandardInformation
);
2761 if (NT_SUCCESS(Status
))
2763 /* First, verify the checksum */
2764 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2769 /* Set checksum failure */
2770 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2774 /* Make sure it's a real image */
2775 NtHeaders
= RtlImageNtHeader(ViewBase
);
2778 /* Set checksum failure */
2779 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2783 /* Make sure it's for the correct architecture */
2784 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2785 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2787 /* Set protection failure */
2788 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2792 /* Check that it's a valid SMP image if we have more then one CPU */
2793 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2795 /* Otherwise it's not the right image */
2796 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2800 /* Unmap the section, close the handle, and return status */
2802 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2803 KeUnstackDetachProcess(&ApcState
);
2804 ZwClose(SectionHandle
);
2810 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2811 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2812 IN PUNICODE_STRING LoadedName OPTIONAL
,
2814 OUT PVOID
*ModuleObject
,
2815 OUT PVOID
*ImageBaseAddress
)
2817 PVOID ModuleLoadBase
= NULL
;
2819 HANDLE FileHandle
= NULL
;
2820 OBJECT_ATTRIBUTES ObjectAttributes
;
2821 IO_STATUS_BLOCK IoStatusBlock
;
2822 PIMAGE_NT_HEADERS NtHeader
;
2823 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2824 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2825 ULONG EntrySize
, DriverSize
;
2826 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2827 PCHAR MissingApiName
, Buffer
;
2828 PWCHAR MissingDriverName
;
2829 HANDLE SectionHandle
;
2830 ACCESS_MASK DesiredAccess
;
2831 PVOID Section
= NULL
;
2832 BOOLEAN LockOwned
= FALSE
;
2833 PLIST_ENTRY NextEntry
;
2834 IMAGE_INFO ImageInfo
;
2838 /* Detect session-load */
2842 ASSERT(NamePrefix
== NULL
);
2843 ASSERT(LoadedName
== NULL
);
2845 /* Make sure the process is in session too */
2846 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2849 /* Allocate a buffer we'll use for names */
2850 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2851 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2853 /* Check for a separator */
2854 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2859 /* Loop the path until we get to the base name */
2860 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2861 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2863 /* Get the length */
2864 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2865 BaseLength
*= sizeof(WCHAR
);
2867 /* Setup the string */
2868 BaseName
.Length
= (USHORT
)BaseLength
;
2869 BaseName
.Buffer
= p
;
2873 /* Otherwise, we already have a base name */
2874 BaseName
.Length
= FileName
->Length
;
2875 BaseName
.Buffer
= FileName
->Buffer
;
2878 /* Setup the maximum length */
2879 BaseName
.MaximumLength
= BaseName
.Length
;
2881 /* Now compute the base directory */
2882 BaseDirectory
= *FileName
;
2883 BaseDirectory
.Length
-= BaseName
.Length
;
2884 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2886 /* And the prefix, which for now is just the name itself */
2887 PrefixName
= *FileName
;
2889 /* Check if we have a prefix */
2890 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2892 /* Check if we already have a name, use it instead */
2893 if (LoadedName
) BaseName
= *LoadedName
;
2895 /* Check for loader snap debugging */
2896 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2898 /* Print out standard string */
2899 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2900 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2903 /* Acquire the load lock */
2905 ASSERT(LockOwned
== FALSE
);
2907 KeEnterCriticalRegion();
2908 KeWaitForSingleObject(&MmSystemLoadLock
,
2914 /* Scan the module list */
2915 NextEntry
= PsLoadedModuleList
.Flink
;
2916 while (NextEntry
!= &PsLoadedModuleList
)
2918 /* Get the entry and compare the names */
2919 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2920 LDR_DATA_TABLE_ENTRY
,
2922 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2924 /* Found it, break out */
2929 NextEntry
= NextEntry
->Flink
;
2932 /* Check if we found the image */
2933 if (NextEntry
!= &PsLoadedModuleList
)
2935 /* Check if we had already mapped a section */
2938 /* Dereference and clear */
2939 ObDereferenceObject(Section
);
2943 /* Check if this was supposed to be a session load */
2946 /* It wasn't, so just return the data */
2947 *ModuleObject
= LdrEntry
;
2948 *ImageBaseAddress
= LdrEntry
->DllBase
;
2949 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2953 /* We don't support session loading yet */
2954 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
2955 Status
= STATUS_NOT_IMPLEMENTED
;
2963 /* It wasn't loaded, and we didn't have a previous attempt */
2964 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2965 KeLeaveCriticalRegion();
2968 /* Check if KD is enabled */
2969 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2971 /* FIXME: Attempt to get image from KD */
2974 /* We don't have a valid entry */
2977 /* Setup image attributes */
2978 InitializeObjectAttributes(&ObjectAttributes
,
2980 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2984 /* Open the image */
2985 Status
= ZwOpenFile(&FileHandle
,
2989 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2991 if (!NT_SUCCESS(Status
))
2993 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
2999 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
3000 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
3001 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
3002 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
3008 /* Check if this is a session-load */
3011 /* Then we only need read and execute */
3012 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
3016 /* Otherwise, we can allow write access */
3017 DesiredAccess
= SECTION_ALL_ACCESS
;
3020 /* Initialize the attributes for the section */
3021 InitializeObjectAttributes(&ObjectAttributes
,
3023 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3027 /* Create the section */
3028 Status
= ZwCreateSection(&SectionHandle
,
3035 if (!NT_SUCCESS(Status
))
3037 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3041 /* Now get the section pointer */
3042 Status
= ObReferenceObjectByHandle(SectionHandle
,
3043 SECTION_MAP_EXECUTE
,
3044 MmSectionObjectType
,
3048 ZwClose(SectionHandle
);
3049 if (!NT_SUCCESS(Status
)) goto Quickie
;
3051 /* Check if this was supposed to be a session-load */
3054 /* We don't support session loading yet */
3055 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3059 /* Check the loader list again, we should end up in the path below */
3064 /* We don't have a valid entry */
3068 /* Load the image */
3069 Status
= MiLoadImageSection(&Section
,
3074 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3076 /* Get the size of the driver */
3077 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageInformation
.ImageFileSize
;
3079 /* Make sure we're not being loaded into session space */
3082 /* Check for success */
3083 if (NT_SUCCESS(Status
))
3085 /* Support large pages for drivers */
3086 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3092 /* Dereference the section */
3093 ObDereferenceObject(Section
);
3097 /* Check for failure of the load earlier */
3098 if (!NT_SUCCESS(Status
))
3100 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3104 /* Relocate the driver */
3105 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3109 STATUS_CONFLICTING_ADDRESSES
,
3110 STATUS_INVALID_IMAGE_FORMAT
);
3111 if (!NT_SUCCESS(Status
))
3113 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3117 /* Get the NT Header */
3118 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3120 /* Calculate the size we'll need for the entry and allocate it */
3121 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3123 sizeof(UNICODE_NULL
);
3125 /* Allocate the entry */
3126 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3130 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3134 /* Setup the entry */
3135 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3136 LdrEntry
->LoadCount
= 1;
3137 LdrEntry
->LoadedImports
= LoadedImports
;
3138 LdrEntry
->PatchInformation
= NULL
;
3140 /* Check the version */
3141 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3142 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3144 /* Mark this image as a native image */
3145 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3148 /* Setup the rest of the entry */
3149 LdrEntry
->DllBase
= ModuleLoadBase
;
3150 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3151 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3152 LdrEntry
->SizeOfImage
= DriverSize
;
3153 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3154 LdrEntry
->SectionPointer
= Section
;
3156 /* Now write the DLL name */
3157 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3158 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3159 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3161 /* Copy and null-terminate it */
3162 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3165 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3167 /* Now allocate the full name */
3168 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3170 sizeof(UNICODE_NULL
),
3172 if (!LdrEntry
->FullDllName
.Buffer
)
3174 /* Don't fail, just set it to zero */
3175 LdrEntry
->FullDllName
.Length
= 0;
3176 LdrEntry
->FullDllName
.MaximumLength
= 0;
3181 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3182 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3184 /* Copy and null-terminate */
3185 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3188 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3192 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3194 /* Resolve imports */
3195 MissingApiName
= Buffer
;
3196 MissingDriverName
= NULL
;
3197 Status
= MiResolveImageReferences(ModuleLoadBase
,
3203 if (!NT_SUCCESS(Status
))
3205 BOOLEAN NeedToFreeString
= FALSE
;
3207 /* If the lowest bit is set to 1, this is a hint that we need to free */
3208 if (*(ULONG_PTR
*)&MissingDriverName
& 1)
3210 NeedToFreeString
= TRUE
;
3211 *(ULONG_PTR
*)&MissingDriverName
&= ~1;
3214 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3215 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3216 MissingDriverName
, MissingApiName
);
3218 if (NeedToFreeString
)
3220 ExFreePoolWithTag(MissingDriverName
, TAG_LDR_WSTR
);
3224 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3226 /* Check if we need to free the name */
3227 if (LdrEntry
->FullDllName
.Buffer
)
3230 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3233 /* Free the entry itself */
3234 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3239 /* Update the loader entry */
3240 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3241 LDRP_ENTRY_PROCESSED
|
3243 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3244 LdrEntry
->LoadedImports
= LoadedImports
;
3246 /* FIXME: Call driver verifier's loader function */
3248 /* Write-protect the system image */
3249 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3251 /* Check if notifications are enabled */
3252 if (PsImageNotifyEnabled
)
3254 /* Fill out the notification data */
3255 ImageInfo
.Properties
= 0;
3256 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3257 ImageInfo
.SystemModeImage
= TRUE
;
3258 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3259 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3260 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3262 /* Send the notification */
3263 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3266 #if defined(KDBG) || defined(_WINKD_)
3267 /* MiCacheImageSymbols doesn't detect rossym */
3270 /* Check if there's symbols */
3271 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3274 /* Check if the system root is present */
3275 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3276 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3278 /* Add the system root */
3279 UnicodeTemp
= PrefixName
;
3280 UnicodeTemp
.Buffer
+= 11;
3281 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3284 &SharedUserData
->NtSystemRoot
[2],
3289 /* Build the name */
3290 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3293 /* Setup the ansi string */
3294 RtlInitString(&AnsiTemp
, Buffer
);
3296 /* Notify the debugger */
3297 DbgLoadImageSymbols(&AnsiTemp
,
3299 (ULONG_PTR
)ZwCurrentProcess());
3300 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3303 /* Page the driver */
3304 ASSERT(Section
== NULL
);
3305 MiEnablePagingOfDriver(LdrEntry
);
3307 /* Return pointers */
3308 *ModuleObject
= LdrEntry
;
3309 *ImageBaseAddress
= LdrEntry
->DllBase
;
3312 /* Check if we have the lock acquired */
3315 /* Release the lock */
3316 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3317 KeLeaveCriticalRegion();
3321 /* If we have a file handle, close it */
3322 if (FileHandle
) ZwClose(FileHandle
);
3324 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3325 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3327 /* Free the name buffer and return status */
3328 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3332 PLDR_DATA_TABLE_ENTRY
3334 MiLookupDataTableEntry(IN PVOID Address
)
3336 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3337 PLIST_ENTRY NextEntry
;
3341 NextEntry
= PsLoadedModuleList
.Flink
;
3344 /* Get the loader entry */
3345 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3346 LDR_DATA_TABLE_ENTRY
,
3349 /* Check if the address matches */
3350 if ((Address
>= LdrEntry
->DllBase
) &&
3351 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3352 LdrEntry
->SizeOfImage
)))
3355 FoundEntry
= LdrEntry
;
3360 NextEntry
= NextEntry
->Flink
;
3361 } while(NextEntry
!= &PsLoadedModuleList
);
3363 /* Return the entry */
3367 /* PUBLIC FUNCTIONS ***********************************************************/
3374 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3376 PMMPTE StartPte
, EndPte
;
3377 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3380 /* Get the loader entry */
3381 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3382 if (!LdrEntry
) return NULL
;
3384 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3385 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3387 /* Don't do anything, just return the base address */
3388 return LdrEntry
->DllBase
;
3391 /* Wait for active DPCs to finish before we page out the driver */
3392 KeFlushQueuedDpcs();
3394 /* Get the PTE range for the whole driver image */
3395 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3396 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3398 /* Enable paging for the PTE range */
3399 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3400 MiSetPagingOfDriver(StartPte
, EndPte
);
3402 /* Return the base address */
3403 return LdrEntry
->DllBase
;
3411 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3421 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3423 PVOID ProcAddress
= NULL
;
3424 ANSI_STRING AnsiRoutineName
;
3426 PLIST_ENTRY NextEntry
;
3427 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3428 BOOLEAN Found
= FALSE
;
3429 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3430 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3433 /* Convert routine to ansi name */
3434 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3437 if (!NT_SUCCESS(Status
)) return NULL
;
3440 KeEnterCriticalRegion();
3441 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3443 /* Loop the loaded module list */
3444 NextEntry
= PsLoadedModuleList
.Flink
;
3445 while (NextEntry
!= &PsLoadedModuleList
)
3448 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3449 LDR_DATA_TABLE_ENTRY
,
3452 /* Check if it's the kernel or HAL */
3453 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3459 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3466 /* Check if we found a valid binary */
3469 /* Find the procedure name */
3470 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3473 /* Break out if we found it or if we already tried both modules */
3474 if (ProcAddress
) break;
3475 if (Modules
== 2) break;
3479 NextEntry
= NextEntry
->Flink
;
3482 /* Release the lock */
3483 ExReleaseResourceLite(&PsLoadedModuleResource
);
3484 KeLeaveCriticalRegion();
3486 /* Free the string and return */
3487 RtlFreeAnsiString(&AnsiRoutineName
);