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 <mm/ARM3/miarm.h>
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
;
103 PFN_NUMBER PageFrameIndex
;
106 /* Detect session load */
110 UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n");
111 return STATUS_NOT_IMPLEMENTED
;
114 /* Not session load, shouldn't have an entry */
115 ASSERT(LdrEntry
== NULL
);
117 /* Attach to the system process */
118 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
120 /* Check if we need to load symbols */
121 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
125 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
129 Process
= PsGetCurrentProcess();
130 Status
= MmMapViewOfSection(Section
,
141 /* Re-enable the flag */
142 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
144 /* Check if we failed with distinguished status code */
145 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
147 /* Change it to something more generic */
148 Status
= STATUS_INVALID_IMAGE_FORMAT
;
151 /* Now check if we failed */
152 if (!NT_SUCCESS(Status
))
154 /* Detach and return */
155 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status
);
156 KeUnstackDetachProcess(&ApcState
);
160 /* Reserve system PTEs needed */
161 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageInformation
.ImageFileSize
) >> PAGE_SHIFT
;
162 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
165 DPRINT1("MiReserveSystemPtes failed\n");
166 KeUnstackDetachProcess(&ApcState
);
167 return STATUS_INSUFFICIENT_RESOURCES
;
170 /* New driver base */
171 LastPte
= PointerPte
+ PteCount
;
172 DriverBase
= MiPteToAddress(PointerPte
);
174 /* The driver is here */
175 *ImageBase
= DriverBase
;
176 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName
, DriverBase
, PteCount
);
178 /* Lock the PFN database */
179 OldIrql
= MiAcquirePfnLock();
181 /* Loop the new driver PTEs */
182 TempPte
= ValidKernelPte
;
183 while (PointerPte
< LastPte
)
185 /* Make sure the PTE is not valid for whatever reason */
186 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
188 /* Some debug stuff */
189 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
191 if (FileName
->Buffer
)
195 pos
= wcsrchr(FileName
->Buffer
, '\\');
196 len
= wcslen(pos
) * sizeof(WCHAR
);
197 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
202 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
204 /* Initialize its PFN entry */
205 MiInitializePfn(PageFrameIndex
, PointerPte
, TRUE
);
208 TempPte
.u
.Hard
.PageFrameNumber
= PageFrameIndex
;
209 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
215 /* Release the PFN lock */
216 MiReleasePfnLock(OldIrql
);
219 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
221 /* Now unmap the view */
222 Status
= MmUnmapViewOfSection(Process
, Base
);
223 ASSERT(NT_SUCCESS(Status
));
225 /* Detach and return status */
226 KeUnstackDetachProcess(&ApcState
);
232 MiLocateExportName(IN PVOID DllBase
,
236 PUSHORT OrdinalTable
;
237 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
238 LONG Low
= 0, Mid
= 0, High
, Ret
;
245 /* Get the export directory */
246 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
248 IMAGE_DIRECTORY_ENTRY_EXPORT
,
250 if (!ExportDirectory
) return NULL
;
252 /* Setup name tables */
253 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
254 ExportDirectory
->AddressOfNames
);
255 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
256 ExportDirectory
->AddressOfNameOrdinals
);
258 /* Do a binary search */
259 High
= ExportDirectory
->NumberOfNames
- 1;
262 /* Get new middle value */
263 Mid
= (Low
+ High
) >> 1;
266 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
284 /* Check if we couldn't find it */
285 if (High
< Low
) return NULL
;
287 /* Otherwise, this is the ordinal */
288 Ordinal
= OrdinalTable
[Mid
];
290 /* Resolve the address and write it */
291 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
292 ExportDirectory
->AddressOfFunctions
);
293 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
295 /* Check if the function is actually a forwarder */
296 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
297 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
309 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
310 IN PLIST_ENTRY ListHead
)
312 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
313 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
314 PMM_DLL_INITIALIZE DllInit
;
315 UNICODE_STRING RegPath
, ImportName
;
318 /* Try to see if the image exports a DllInitialize routine */
319 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
321 if (!DllInit
) return STATUS_SUCCESS
;
323 /* Do a temporary copy of BaseDllName called ImportName
324 * because we'll alter the length of the string
326 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
327 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
328 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
330 /* Obtain the path to this dll's service in the registry */
331 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
332 ImportName
.Length
+ sizeof(UNICODE_NULL
);
333 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
334 RegPath
.MaximumLength
,
337 /* Check if this allocation was unsuccessful */
338 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
340 /* Build and append the service name itself */
341 RegPath
.Length
= ServicesKeyName
.Length
;
342 RtlCopyMemory(RegPath
.Buffer
,
343 ServicesKeyName
.Buffer
,
344 ServicesKeyName
.Length
);
346 /* Check if there is a dot in the filename */
347 if (wcschr(ImportName
.Buffer
, L
'.'))
349 /* Remove the extension */
350 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
351 ImportName
.Buffer
) * sizeof(WCHAR
);
354 /* Append service name (the basename without extension) */
355 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
357 /* Now call the DllInit func */
358 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
359 Status
= DllInit(&RegPath
);
362 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
364 /* Return status value which DllInitialize returned */
370 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
376 /* Get the unload routine */
377 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
378 if (!Func
) return FALSE
;
380 /* Call it and check for success */
382 if (!NT_SUCCESS(Status
)) return FALSE
;
384 /* Lie about the load count so we can unload the image */
385 ASSERT(LdrEntry
->LoadCount
== 0);
386 LdrEntry
->LoadCount
= 1;
388 /* Unload it and return true */
389 MmUnloadSystemImage(LdrEntry
);
395 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
398 LOAD_IMPORTS SingleEntry
;
399 PLDR_DATA_TABLE_ENTRY LdrEntry
;
400 PVOID CurrentImports
;
403 /* Check if there's no imports or if we're a boot driver */
404 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
405 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
406 (ImportList
->Count
== 0))
408 /* Then there's nothing to do */
409 return STATUS_SUCCESS
;
412 /* Check for single-entry */
413 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
416 SingleEntry
.Count
= 1;
417 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
419 /* Use this as the import list */
420 ImportList
= &SingleEntry
;
423 /* Loop the import list */
424 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
427 LdrEntry
= ImportList
->Entry
[i
];
428 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
430 /* Skip boot loaded images */
431 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
433 /* Dereference the entry */
434 ASSERT(LdrEntry
->LoadCount
>= 1);
435 if (!--LdrEntry
->LoadCount
)
437 /* Save the import data in case unload fails */
438 CurrentImports
= LdrEntry
->LoadedImports
;
440 /* This is the last entry */
441 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
442 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
444 /* Unloading worked, parse this DLL's imports too */
445 MiDereferenceImports(CurrentImports
);
447 /* Check if we had valid imports */
448 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) &&
449 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) &&
450 !((ULONG_PTR
)CurrentImports
& MM_SYSLDR_SINGLE_ENTRY
))
453 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
458 /* Unload failed, restore imports */
459 LdrEntry
->LoadedImports
= CurrentImports
;
465 return STATUS_SUCCESS
;
470 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
474 /* Check if there's no imports or we're a boot driver or only one entry */
475 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
476 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
477 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
483 /* Otherwise, free the import list */
484 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
485 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
490 MiFindExportedRoutineByName(IN PVOID DllBase
,
491 IN PANSI_STRING ExportName
)
494 PUSHORT OrdinalTable
;
495 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
496 LONG Low
= 0, Mid
= 0, High
, Ret
;
503 /* Get the export directory */
504 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
506 IMAGE_DIRECTORY_ENTRY_EXPORT
,
508 if (!ExportDirectory
) return NULL
;
510 /* Setup name tables */
511 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
512 ExportDirectory
->AddressOfNames
);
513 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
514 ExportDirectory
->AddressOfNameOrdinals
);
516 /* Do a binary search */
517 High
= ExportDirectory
->NumberOfNames
- 1;
520 /* Get new middle value */
521 Mid
= (Low
+ High
) >> 1;
524 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
542 /* Check if we couldn't find it */
543 if (High
< Low
) return NULL
;
545 /* Otherwise, this is the ordinal */
546 Ordinal
= OrdinalTable
[Mid
];
548 /* Validate the ordinal */
549 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
551 /* Resolve the address and write it */
552 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
553 ExportDirectory
->AddressOfFunctions
);
554 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
557 ASSERT((Function
< (PVOID
)ExportDirectory
) ||
558 (Function
> (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
565 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
570 /* Acquire module list lock */
571 KeEnterCriticalRegion();
572 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
574 /* Acquire the spinlock too as we will insert or remove the entry */
575 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
577 /* Insert or remove from the list */
579 InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
);
581 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
584 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
585 ExReleaseResourceLite(&PsLoadedModuleResource
);
586 KeLeaveCriticalRegion();
592 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
597 ULONG_PTR OldBaseTop
, Delta
;
598 PLDR_DATA_TABLE_ENTRY LdrEntry
;
599 PLIST_ENTRY NextEntry
;
602 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
603 // since a real version of Windows would fail at this point, but they seem
604 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
605 // a feature which isn't even used by Windows. Priorities, priorities...
606 // Please note that Microsoft WDK EULA and license prohibits using
607 // the information contained within it for the generation of "non-Windows"
608 // drivers, which is precisely what LD will generate, since an LD driver
609 // will not load on Windows.
611 #ifdef _WORKING_LINKER_
614 PULONG_PTR ImageThunk
;
615 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
617 /* Calculate the top and delta */
618 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
619 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
621 /* Loop the loader block */
622 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
623 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
624 NextEntry
= NextEntry
->Flink
)
626 /* Get the loader entry */
627 LdrEntry
= CONTAINING_RECORD(NextEntry
,
628 LDR_DATA_TABLE_ENTRY
,
630 #ifdef _WORKING_LINKER_
632 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
634 IMAGE_DIRECTORY_ENTRY_IAT
,
636 if (!ImageThunk
) continue;
638 /* Make sure we have an IAT */
639 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
640 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
642 /* Check if it's within this module */
643 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
646 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
647 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
648 *ImageThunk
+= Delta
;
652 /* Get the import table */
653 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
655 IMAGE_DIRECTORY_ENTRY_IMPORT
,
657 if (!ImportDescriptor
) continue;
659 /* Make sure we have an IAT */
660 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
661 while ((ImportDescriptor
->Name
) &&
662 (ImportDescriptor
->OriginalFirstThunk
))
664 /* Get the image thunk */
665 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
666 ImportDescriptor
->FirstThunk
);
669 /* Check if it's within this module */
670 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
673 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
674 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
675 *ImageThunk
+= Delta
;
678 /* Go to the next thunk */
682 /* Go to the next import */
691 MiSnapThunk(IN PVOID DllBase
,
693 IN PIMAGE_THUNK_DATA Name
,
694 IN PIMAGE_THUNK_DATA Address
,
695 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
697 IN BOOLEAN SnapForwarder
,
698 OUT PCHAR
*MissingApi
)
703 PUSHORT OrdinalTable
;
704 PIMAGE_IMPORT_BY_NAME NameImport
;
706 ULONG Low
= 0, Mid
= 0, High
;
709 PCHAR MissingForwarder
;
710 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
713 UNICODE_STRING ForwarderName
;
714 PLIST_ENTRY NextEntry
;
715 PLDR_DATA_TABLE_ENTRY LdrEntry
;
716 ULONG ForwardExportSize
;
717 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
718 PIMAGE_IMPORT_BY_NAME ForwardName
;
719 SIZE_T ForwardLength
;
720 IMAGE_THUNK_DATA ForwardThunk
;
723 /* Check if this is an ordinal */
724 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
725 if ((IsOrdinal
) && !(SnapForwarder
))
727 /* Get the ordinal number and set it as missing */
728 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
729 ExportDirectory
->Base
);
730 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
734 /* Get the VA if we don't have to snap */
735 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
736 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
738 /* Copy the procedure name */
739 RtlStringCbCopyA(*MissingApi
,
740 MAXIMUM_FILENAME_LENGTH
,
741 (PCHAR
)&NameImport
->Name
[0]);
743 /* Setup name tables */
744 DPRINT("Import name: %s\n", NameImport
->Name
);
745 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
746 ExportDirectory
->AddressOfNames
);
747 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
748 ExportDirectory
->AddressOfNameOrdinals
);
750 /* Get the hint and check if it's valid */
751 Hint
= NameImport
->Hint
;
752 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
753 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
755 /* We have a match, get the ordinal number from here */
756 Ordinal
= OrdinalTable
[Hint
];
760 /* Do a binary search */
761 High
= ExportDirectory
->NumberOfNames
- 1;
764 /* Get new middle value */
765 Mid
= (Low
+ High
) >> 1;
768 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
786 /* Check if we couldn't find it */
789 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
790 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
793 /* Otherwise, this is the ordinal */
794 Ordinal
= OrdinalTable
[Mid
];
798 /* Check if the ordinal is invalid */
799 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
802 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
806 /* In case the forwarder is missing */
807 MissingForwarder
= NameBuffer
;
809 /* Resolve the address and write it */
810 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
811 ExportDirectory
->AddressOfFunctions
);
812 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
814 /* Assume success from now on */
815 Status
= STATUS_SUCCESS
;
817 /* Check if the function is actually a forwarder */
818 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
819 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
821 /* Now assume failure in case the forwarder doesn't exist */
822 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
824 /* Build the forwarder name */
825 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
826 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
829 DllName
.MaximumLength
= DllName
.Length
;
832 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
836 /* We failed, just return an error */
840 /* Loop the module list */
841 NextEntry
= PsLoadedModuleList
.Flink
;
842 while (NextEntry
!= &PsLoadedModuleList
)
844 /* Get the loader entry */
845 LdrEntry
= CONTAINING_RECORD(NextEntry
,
846 LDR_DATA_TABLE_ENTRY
,
849 /* Check if it matches */
850 if (RtlPrefixUnicodeString(&ForwarderName
,
851 &LdrEntry
->BaseDllName
,
854 /* Get the forwarder export directory */
855 ForwardExportDirectory
=
856 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
858 IMAGE_DIRECTORY_ENTRY_EXPORT
,
860 if (!ForwardExportDirectory
) break;
862 /* Allocate a name entry */
863 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
865 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
866 sizeof(*ForwardName
) +
869 if (!ForwardName
) break;
872 RtlCopyMemory(&ForwardName
->Name
[0],
873 DllName
.Buffer
+ DllName
.Length
,
875 ForwardName
->Hint
= 0;
877 /* Set the new address */
878 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
880 /* Snap the forwarder */
881 Status
= MiSnapThunk(LdrEntry
->DllBase
,
885 ForwardExportDirectory
,
890 /* Free the forwarder name and set the thunk */
891 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
892 Address
->u1
= ForwardThunk
.u1
;
896 /* Go to the next entry */
897 NextEntry
= NextEntry
->Flink
;
901 RtlFreeUnicodeString(&ForwarderName
);
911 MmUnloadSystemImage(IN PVOID ImageHandle
)
913 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
914 PVOID BaseAddress
= LdrEntry
->DllBase
;
917 BOOLEAN HadEntry
= FALSE
;
919 /* Acquire the loader lock */
920 KeEnterCriticalRegion();
921 KeWaitForSingleObject(&MmSystemLoadLock
,
927 /* Check if this driver was loaded at boot and didn't get imports parsed */
928 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
930 /* We should still be alive */
931 ASSERT(LdrEntry
->LoadCount
!= 0);
932 LdrEntry
->LoadCount
--;
934 /* Check if we're still loaded */
935 if (LdrEntry
->LoadCount
) goto Done
;
937 /* We should cleanup... are symbols loaded */
938 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
940 /* Create the ANSI name */
941 Status
= RtlUnicodeStringToAnsiString(&TempName
,
942 &LdrEntry
->BaseDllName
,
944 if (NT_SUCCESS(Status
))
946 /* Unload the symbols */
947 DbgUnLoadImageSymbols(&TempName
,
949 (ULONG_PTR
)PsGetCurrentProcessId());
950 RtlFreeAnsiString(&TempName
);
954 /* FIXME: Free the driver */
955 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
956 //MmFreeSection(LdrEntry->DllBase);
958 /* Check if we're linked in */
959 if (LdrEntry
->InLoadOrderLinks
.Flink
)
962 MiProcessLoaderEntry(LdrEntry
, FALSE
);
966 /* Dereference and clear the imports */
967 MiDereferenceImports(LdrEntry
->LoadedImports
);
968 MiClearImports(LdrEntry
);
970 /* Check if the entry needs to go away */
973 /* Check if it had a name */
974 if (LdrEntry
->FullDllName
.Buffer
)
977 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
980 /* Check if we had a section */
981 if (LdrEntry
->SectionPointer
)
984 ObDereferenceObject(LdrEntry
->SectionPointer
);
988 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
991 /* Release the system lock and return */
993 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
994 KeLeaveCriticalRegion();
995 return STATUS_SUCCESS
;
1000 MiResolveImageReferences(IN PVOID ImageBase
,
1001 IN PUNICODE_STRING ImageFileDirectory
,
1002 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1003 OUT PCHAR
*MissingApi
,
1004 OUT PWCHAR
*MissingDriver
,
1005 OUT PLOAD_IMPORTS
*LoadImports
)
1007 static UNICODE_STRING DriversFolderName
= RTL_CONSTANT_STRING(L
"drivers\\");
1008 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
1009 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
1010 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
1011 PLOAD_IMPORTS LoadedImports
, NewImports
;
1012 ULONG GdiLink
, NormalLink
, i
;
1013 BOOLEAN ReferenceNeeded
, Loaded
;
1014 ANSI_STRING TempString
;
1015 UNICODE_STRING NameString
, DllName
;
1016 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
1017 PVOID ImportBase
, DllBase
;
1018 PLIST_ENTRY NextEntry
;
1019 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1021 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1023 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1024 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1026 /* No name string buffer yet */
1027 NameString
.Buffer
= NULL
;
1029 /* Assume no imports */
1030 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1032 /* Get the import descriptor */
1033 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1035 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1037 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1039 /* Loop all imports to count them */
1040 for (CurrentImport
= ImportDescriptor
;
1041 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1048 /* Make sure we have non-zero imports */
1051 /* Calculate and allocate the list we'll need */
1052 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1053 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1059 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1060 LoadedImports
->Count
= ImportCount
;
1066 LoadedImports
= NULL
;
1069 /* Reset the import count and loop descriptors again */
1070 ImportCount
= GdiLink
= NormalLink
= 0;
1071 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1074 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1076 /* Check if this is a GDI driver */
1078 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1080 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1081 NormalLink
= NormalLink
|
1082 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1083 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1084 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1085 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1087 /* Check if this is a valid GDI driver */
1088 if ((GdiLink
) && (NormalLink
))
1090 /* It's not, it's importing stuff it shouldn't be! */
1091 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1095 /* Check for user-mode printer or video card drivers, which don't belong */
1096 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1097 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1098 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1099 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1100 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1101 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1103 /* This is not kernel code */
1104 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1108 /* Check if this is a "core" import, which doesn't get referenced */
1109 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1110 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1111 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1113 /* Don't reference this */
1114 ReferenceNeeded
= FALSE
;
1118 /* Reference these modules */
1119 ReferenceNeeded
= TRUE
;
1122 /* Now setup a unicode string for the import */
1123 RtlInitAnsiString(&TempString
, ImportName
);
1124 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1125 if (!NT_SUCCESS(Status
))
1131 /* We don't support name prefixes yet */
1132 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1134 /* Remember that we haven't loaded the import at this point */
1139 /* Loop the driver list */
1140 NextEntry
= PsLoadedModuleList
.Flink
;
1141 while (NextEntry
!= &PsLoadedModuleList
)
1143 /* Get the loader entry and compare the name */
1144 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1145 LDR_DATA_TABLE_ENTRY
,
1147 if (RtlEqualUnicodeString(&NameString
,
1148 &LdrEntry
->BaseDllName
,
1151 /* Get the base address */
1152 ImportBase
= LdrEntry
->DllBase
;
1154 /* Check if we haven't loaded yet, and we need references */
1155 if (!(Loaded
) && (ReferenceNeeded
))
1157 /* Make sure we're not already loading */
1158 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1160 /* Increase the load count */
1161 LdrEntry
->LoadCount
++;
1165 /* Done, break out */
1169 /* Go to the next entry */
1170 NextEntry
= NextEntry
->Flink
;
1173 /* Check if we haven't loaded the import yet */
1176 /* Setup the import DLL name */
1177 DllName
.MaximumLength
= NameString
.Length
+
1178 ImageFileDirectory
->Length
+
1179 sizeof(UNICODE_NULL
);
1180 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1181 DllName
.MaximumLength
,
1183 if (!DllName
.Buffer
)
1185 /* We're out of resources */
1186 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1190 /* Add the import name to the base directory */
1191 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1192 RtlAppendUnicodeStringToString(&DllName
,
1195 /* Load the image */
1196 Status
= MmLoadSystemImage(&DllName
,
1203 /* win32k / GDI drivers can also import from system32 folder */
1204 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) &&
1205 (MI_IS_SESSION_ADDRESS(ImageBase
) || 1)) // HACK
1207 /* Free the old name buffer */
1208 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1210 /* Calculate size for a string the adds 'drivers\' */
1211 DllName
.MaximumLength
+= DriversFolderName
.Length
;
1213 /* Allocate the new buffer */
1214 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1215 DllName
.MaximumLength
,
1217 if (!DllName
.Buffer
)
1219 /* We're out of resources */
1220 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1224 /* Copy image directory and append 'drivers\' folder name */
1225 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1226 RtlAppendUnicodeStringToString(&DllName
, &DriversFolderName
);
1228 /* Now add the import name */
1229 RtlAppendUnicodeStringToString(&DllName
, &NameString
);
1231 /* Try once again to load the image */
1232 Status
= MmLoadSystemImage(&DllName
,
1240 if (!NT_SUCCESS(Status
))
1242 /* Fill out the information for the error */
1243 *MissingDriver
= DllName
.Buffer
;
1244 *(PULONG
)MissingDriver
|= 1;
1247 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1249 /* Don't free the name */
1250 DllName
.Buffer
= NULL
;
1252 /* Cleanup and return */
1256 /* We can free the DLL Name */
1257 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1258 DllName
.Buffer
= NULL
;
1260 /* We're now loaded */
1264 ASSERT(DllBase
== DllEntry
->DllBase
);
1266 /* Call the initialization routines */
1267 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1268 if (!NT_SUCCESS(Status
))
1270 /* We failed, unload the image */
1271 MmUnloadSystemImage(DllEntry
);
1272 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status
);
1276 /* Loop again to make sure that everything is OK */
1280 /* Check if we're support to reference this import */
1281 if ((ReferenceNeeded
) && (LoadedImports
))
1283 /* Make sure we're not already loading */
1284 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1287 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1292 /* Free the import name */
1293 RtlFreeUnicodeString(&NameString
);
1295 /* Set the missing driver name and get the export directory */
1296 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1297 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1299 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1301 if (!ExportDirectory
)
1303 /* Cleanup and return */
1304 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1305 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1309 /* Make sure we have an IAT */
1310 if (ImportDescriptor
->OriginalFirstThunk
)
1312 /* Get the first thunks */
1313 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1314 ImportDescriptor
->OriginalFirstThunk
);
1315 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1316 ImportDescriptor
->FirstThunk
);
1319 while (OrigThunk
->u1
.AddressOfData
)
1322 Status
= MiSnapThunk(ImportBase
,
1330 if (!NT_SUCCESS(Status
))
1332 /* Cleanup and return */
1336 /* Reset the buffer */
1337 *MissingApi
= MissingApiBuffer
;
1341 /* Go to the next import */
1345 /* Check if we have an import list */
1348 /* Reset the count again, and loop entries */
1350 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1352 if (LoadedImports
->Entry
[i
])
1354 /* Got an entry, OR it with 1 in case it's the single entry */
1355 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1356 MM_SYSLDR_SINGLE_ENTRY
);
1361 /* Check if we had no imports */
1364 /* Free the list and set it to no imports */
1365 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1366 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1368 else if (ImportCount
== 1)
1370 /* Just one entry, we can free the table and only use our entry */
1371 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1372 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1374 else if (ImportCount
!= LoadedImports
->Count
)
1376 /* Allocate a new list */
1377 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1378 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1384 NewImports
->Count
= 0;
1386 /* Loop all the imports */
1387 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1389 /* Make sure it's valid */
1390 if (LoadedImports
->Entry
[i
])
1393 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1394 NewImports
->Count
++;
1398 /* Free the old copy */
1399 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1400 LoadedImports
= NewImports
;
1404 /* Return the list */
1405 *LoadImports
= LoadedImports
;
1408 /* Return success */
1409 return STATUS_SUCCESS
;
1413 /* Cleanup and return */
1414 RtlFreeUnicodeString(&NameString
);
1418 MiDereferenceImports(LoadedImports
);
1419 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1427 MiFreeInitializationCode(IN PVOID InitStart
,
1431 PFN_NUMBER PagesFreed
;
1433 /* Get the start PTE */
1434 PointerPte
= MiAddressToPte(InitStart
);
1435 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1437 /* Compute the number of pages we expect to free */
1438 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
);
1440 /* Try to actually free them */
1441 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1450 MiFindInitializationCode(OUT PVOID
*StartVa
,
1453 ULONG Size
, SectionCount
, Alignment
;
1454 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1455 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1456 PLIST_ENTRY NextEntry
;
1457 PIMAGE_NT_HEADERS NtHeader
;
1458 PIMAGE_SECTION_HEADER Section
, LastSection
, InitSection
;
1460 DBG_UNREFERENCED_LOCAL_VARIABLE(InitSection
);
1462 /* So we don't free our own code yet */
1463 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1465 /* Assume failure */
1468 /* Enter a critical region while we loop the list */
1469 KeEnterCriticalRegion();
1471 /* Loop all loaded modules */
1472 NextEntry
= PsLoadedModuleList
.Flink
;
1473 while (NextEntry
!= &PsLoadedModuleList
)
1475 /* Get the loader entry and its DLL base */
1476 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1477 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1479 /* Only process boot loaded images. Other drivers are processed by
1480 MmFreeDriverInitialization */
1481 if (LdrEntry
->Flags
& LDRP_MM_LOADED
)
1484 NextEntry
= NextEntry
->Flink
;
1488 /* Get the NT header */
1489 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1493 NextEntry
= NextEntry
->Flink
;
1497 /* Get the first section, the section count, and scan them all */
1498 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1499 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1501 while (SectionCount
> 0)
1503 /* Assume failure */
1506 /* Is this the INIT section or a discardable section? */
1507 if ((strncmp((PCCH
)Section
->Name
, "INIT", 5) == 0) ||
1508 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1512 InitSection
= Section
;
1517 /* Pick the biggest size -- either raw or virtual */
1518 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1520 /* Read the section alignment */
1521 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1523 /* Get the start and end addresses */
1524 InitStart
= DllBase
+ Section
->VirtualAddress
;
1525 InitEnd
= ALIGN_UP_BY(InitStart
+ Size
, Alignment
);
1527 /* Align the addresses to PAGE_SIZE */
1528 InitStart
= ALIGN_UP_BY(InitStart
, PAGE_SIZE
);
1529 InitEnd
= ALIGN_DOWN_BY(InitEnd
, PAGE_SIZE
);
1531 /* Have we reached the last section? */
1532 if (SectionCount
== 1)
1535 LastSection
= Section
;
1539 /* We have not, loop all the sections */
1543 /* Keep going until we find a non-discardable section range */
1546 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1548 /* Discardable, so record it, then keep going */
1549 LastSection
= Section
;
1553 /* Non-contigous discard flag, or no flag, break out */
1557 while (SectionCount
> 1);
1560 /* Have we found a discardable or init section? */
1563 /* Pick the biggest size -- either raw or virtual */
1564 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1566 /* Use this as the end of the section address */
1567 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
;
1569 /* Have we reached the last section yet? */
1570 if (SectionCount
!= 1)
1572 /* Then align this accross the session boundary */
1573 InitEnd
= ALIGN_UP_BY(InitEnd
, Alignment
);
1574 InitEnd
= ALIGN_DOWN_BY(InitEnd
, PAGE_SIZE
);
1578 /* Make sure we don't let the init section go past the image */
1579 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1580 if (InitEnd
> ImageEnd
) InitEnd
= ALIGN_UP_BY(ImageEnd
, PAGE_SIZE
);
1582 /* Make sure we have a valid, non-zero init section */
1583 if (InitStart
< InitEnd
)
1585 /* Make sure we are not within this code itself */
1586 if ((InitCode
>= InitStart
) && (InitCode
< InitEnd
))
1588 /* Return it, we can't free ourselves now */
1589 ASSERT(*StartVa
== 0);
1590 *StartVa
= (PVOID
)InitStart
;
1591 *EndVa
= (PVOID
)InitEnd
;
1595 /* This isn't us -- go ahead and free it */
1596 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1597 DPRINT("Freeing init code: %p-%p ('%wZ' @%p : '%s')\n",
1600 &LdrEntry
->BaseDllName
,
1603 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1608 /* Move to the next section */
1613 /* Move to the next module */
1614 NextEntry
= NextEntry
->Flink
;
1617 /* Leave the critical region and return */
1618 KeLeaveCriticalRegion();
1622 * Note: This function assumes that all discardable sections are at the end of
1623 * the PE file. It searches backwards until it finds the non-discardable section
1627 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1629 PMMPTE StartPte
, EndPte
;
1630 PFN_NUMBER PageCount
;
1633 PIMAGE_NT_HEADERS NtHeader
;
1634 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1636 /* Get the base address and the page count */
1637 DllBase
= LdrEntry
->DllBase
;
1638 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1640 /* Get the last PTE in this image */
1641 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1643 /* Get the NT header */
1644 NtHeader
= RtlImageNtHeader(DllBase
);
1645 if (!NtHeader
) return;
1647 /* Get the last section and loop each section backwards */
1648 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1649 DiscardSection
= NULL
;
1650 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1652 /* Go back a section and check if it's discardable */
1654 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1656 /* It is, select it for freeing */
1657 DiscardSection
= Section
;
1661 /* No more discardable sections exist, bail out */
1666 /* Bail out if there's nothing to free */
1667 if (!DiscardSection
) return;
1669 /* Push the DLL base to the first disacrable section, and get its PTE */
1670 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1671 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1672 StartPte
= MiAddressToPte(DllBase
);
1674 /* Check how many pages to free total */
1675 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1676 if (!PageCount
) return;
1678 /* Delete this many PTEs */
1679 MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1685 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1687 PLIST_ENTRY NextEntry
;
1689 PIMAGE_NT_HEADERS NtHeader
;
1690 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1691 PIMAGE_FILE_HEADER FileHeader
;
1692 BOOLEAN ValidRelocs
;
1693 PIMAGE_DATA_DIRECTORY DataDirectory
;
1694 PVOID DllBase
, NewImageAddress
;
1696 PMMPTE PointerPte
, StartPte
, LastPte
;
1699 MMPTE TempPte
, OldPte
;
1701 /* Loop driver list */
1702 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1703 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1704 NextEntry
= NextEntry
->Flink
)
1706 /* Get the loader entry and NT header */
1707 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1708 LDR_DATA_TABLE_ENTRY
,
1710 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1713 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1715 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1716 &LdrEntry
->FullDllName
);
1718 /* Get the first PTE and the number of PTEs we'll need */
1719 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1720 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1721 LastPte
= StartPte
+ PteCount
;
1725 while (PointerPte
< LastPte
)
1728 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1729 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1730 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1731 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1735 /* Skip kernel and HAL */
1736 /* ROS HACK: Skip BOOTVID/KDCOM too */
1738 if (i
<= 4) continue;
1740 /* Skip non-drivers */
1741 if (!NtHeader
) continue;
1743 /* Get the file header and make sure we can relocate */
1744 FileHeader
= &NtHeader
->FileHeader
;
1745 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1746 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1747 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1749 /* Everything made sense until now, check the relocation section too */
1750 DataDirectory
= &NtHeader
->OptionalHeader
.
1751 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1752 if (!DataDirectory
->VirtualAddress
)
1754 /* We don't really have relocations */
1755 ValidRelocs
= FALSE
;
1759 /* Make sure the size is valid */
1760 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1761 LdrEntry
->SizeOfImage
)
1763 /* They're not, skip */
1767 /* We have relocations */
1771 /* Remember the original address */
1772 DllBase
= LdrEntry
->DllBase
;
1775 PointerPte
= StartPte
;
1776 while (PointerPte
< LastPte
)
1778 /* Mark the page modified in the PFN database */
1779 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1780 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1781 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1782 Pfn1
->u3
.e1
.Modified
= TRUE
;
1788 /* Now reserve system PTEs for the image */
1789 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1792 /* Shouldn't happen */
1793 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1797 /* This is the new virtual address for the module */
1798 LastPte
= PointerPte
+ PteCount
;
1799 NewImageAddress
= MiPteToAddress(PointerPte
);
1802 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1803 ASSERT(ExpInitializationPhase
== 0);
1805 /* Loop the new driver PTEs */
1806 TempPte
= ValidKernelPte
;
1807 while (PointerPte
< LastPte
)
1809 /* Copy the old data */
1811 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1813 /* Set page number from the loader's memory */
1814 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1817 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1824 /* Update position */
1825 PointerPte
-= PteCount
;
1828 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1830 /* Set the image base to the address where the loader put it */
1831 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1833 /* Check if we had relocations */
1836 /* Relocate the image */
1837 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1841 STATUS_CONFLICTING_ADDRESSES
,
1842 STATUS_INVALID_IMAGE_FORMAT
);
1843 if (!NT_SUCCESS(Status
))
1845 /* This shouldn't happen */
1846 ERROR_FATAL("Relocations failed!\n");
1851 /* Update the loader entry */
1852 LdrEntry
->DllBase
= NewImageAddress
;
1854 /* Update the thunks */
1855 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1856 MiUpdateThunks(LoaderBlock
,
1859 LdrEntry
->SizeOfImage
);
1861 /* Update the loader entry */
1862 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1863 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1864 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1865 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1867 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1874 MiBuildImportsForBootDrivers(VOID
)
1876 PLIST_ENTRY NextEntry
, NextEntry2
;
1877 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1878 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1879 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1880 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1881 PLOAD_IMPORTS LoadedImports
;
1882 ULONG LoadedImportsSize
, ImportSize
;
1883 PULONG_PTR ImageThunk
;
1884 ULONG_PTR DllBase
, DllEnd
;
1885 ULONG Modules
= 0, i
, j
= 0;
1886 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1888 /* Initialize variables */
1889 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1891 /* Loop the loaded module list... we are early enough that no lock is needed */
1892 NextEntry
= PsLoadedModuleList
.Flink
;
1893 while (NextEntry
!= &PsLoadedModuleList
)
1896 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1897 LDR_DATA_TABLE_ENTRY
,
1900 /* Check if it's the kernel or HAL */
1901 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1904 KernelEntry
= LdrEntry
;
1906 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1909 HalEntry
= LdrEntry
;
1912 /* Check if this is a driver DLL */
1913 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1915 /* Check if this is the HAL or kernel */
1916 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1918 /* Add a reference */
1919 LdrEntry
->LoadCount
= 1;
1923 /* No referencing needed */
1924 LdrEntry
->LoadCount
= 0;
1929 /* Add a reference for all other modules as well */
1930 LdrEntry
->LoadCount
= 1;
1933 /* Remember this came from the loader */
1934 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1937 NextEntry
= NextEntry
->Flink
;
1941 /* We must have at least found the kernel and HAL */
1942 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1944 /* Allocate the list */
1945 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1946 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1948 /* Loop the loaded module list again */
1949 NextEntry
= PsLoadedModuleList
.Flink
;
1950 while (NextEntry
!= &PsLoadedModuleList
)
1953 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1954 LDR_DATA_TABLE_ENTRY
,
1956 #ifdef _WORKING_LOADER_
1957 /* Get its imports */
1958 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1960 IMAGE_DIRECTORY_ENTRY_IAT
,
1964 /* Get its imports */
1965 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1967 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1969 if (!ImportDescriptor
)
1973 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1974 NextEntry
= NextEntry
->Flink
;
1978 /* Clear the list and count the number of IAT thunks */
1979 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1980 #ifdef _WORKING_LOADER_
1981 ImportSize
/= sizeof(ULONG_PTR
);
1983 /* Scan the thunks */
1984 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1986 DllBase
= DllEnd
= i
= 0;
1987 while ((ImportDescriptor
->Name
) &&
1988 (ImportDescriptor
->OriginalFirstThunk
))
1990 /* Get the image thunk */
1991 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1992 ImportDescriptor
->FirstThunk
);
1996 /* Do we already have an address? */
1999 /* Is the thunk in the same address? */
2000 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
2002 /* Skip it, we already have a reference for it */
2003 ASSERT(EntryArray
[j
]);
2009 /* Loop the loaded module list to locate this address owner */
2011 NextEntry2
= PsLoadedModuleList
.Flink
;
2012 while (NextEntry2
!= &PsLoadedModuleList
)
2015 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
2016 LDR_DATA_TABLE_ENTRY
,
2019 /* Get the address range for this module */
2020 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
2021 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
2023 /* Check if this IAT entry matches it */
2024 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
2027 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
2028 EntryArray
[j
] = LdrEntry2
;
2032 /* Keep searching */
2033 NextEntry2
= NextEntry2
->Flink
;
2037 /* Do we have a thunk outside the range? */
2038 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
2043 /* Should not be happening */
2044 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2045 LdrEntry
, ImageThunk
, *ImageThunk
);
2048 /* Reset if we hit this */
2051 #ifndef _WORKING_LOADER_
2060 /* Now scan how many imports we really have */
2061 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
2063 /* Skip HAL and kernel */
2064 if ((EntryArray
[i
]) &&
2065 (EntryArray
[i
] != HalEntry
) &&
2066 (EntryArray
[i
] != KernelEntry
))
2068 /* A valid reference */
2069 LastEntry
= EntryArray
[i
];
2074 /* Do we have any imports after all? */
2078 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2080 else if (ImportSize
== 1)
2082 /* A single entry import */
2083 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2084 LastEntry
->LoadCount
++;
2088 /* We need an import table */
2089 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2090 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2093 ASSERT(LoadedImports
);
2095 /* Save the count */
2096 LoadedImports
->Count
= ImportSize
;
2098 /* Now copy all imports */
2099 for (i
= 0, j
= 0; i
< Modules
; i
++)
2101 /* Skip HAL and kernel */
2102 if ((EntryArray
[i
]) &&
2103 (EntryArray
[i
] != HalEntry
) &&
2104 (EntryArray
[i
] != KernelEntry
))
2106 /* A valid reference */
2107 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2108 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2109 EntryArray
[i
]->LoadCount
++;
2114 /* Should had as many entries as we expected */
2115 ASSERT(j
== ImportSize
);
2116 LdrEntry
->LoadedImports
= LoadedImports
;
2120 NextEntry
= NextEntry
->Flink
;
2123 /* Free the initial array */
2124 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2126 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2128 /* Kernel and HAL are loaded at boot */
2129 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2130 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2132 /* All worked well */
2133 return STATUS_SUCCESS
;
2139 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2142 PIMAGE_NT_HEADERS NtHeaders
;
2143 PIMAGE_SECTION_HEADER SectionHeader
;
2144 ULONG Sections
, Size
;
2146 /* Get the kernel section header */
2147 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2148 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2149 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2151 /* Loop all the sections */
2152 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2155 /* Grab the size of the section */
2156 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2158 /* Check for .RSRC section */
2159 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2161 /* Remember the PTEs so we can modify them later */
2162 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2163 SectionHeader
->VirtualAddress
);
2164 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2165 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2167 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2169 /* POOLCODE vs. POOLMI */
2170 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2172 /* Found Ex* Pool code */
2173 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2174 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2176 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2178 /* Found Mm* Pool code */
2179 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2180 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2183 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2184 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2186 /* Found MISYSPTE (Mm System PTE code)*/
2187 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2188 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2200 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2202 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2203 PLIST_ENTRY ListHead
, NextEntry
;
2206 /* Setup the loaded module list and locks */
2207 ExInitializeResourceLite(&PsLoadedModuleResource
);
2208 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2209 InitializeListHead(&PsLoadedModuleList
);
2211 /* Get loop variables and the kernel entry */
2212 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2213 NextEntry
= ListHead
->Flink
;
2214 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2215 LDR_DATA_TABLE_ENTRY
,
2217 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2219 /* Locate resource section, pool code, and system pte code */
2220 MiLocateKernelSections(LdrEntry
);
2222 /* Loop the loader block */
2223 while (NextEntry
!= ListHead
)
2225 /* Get the loader entry */
2226 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2227 LDR_DATA_TABLE_ENTRY
,
2230 /* FIXME: ROS HACK. Make sure this is a driver */
2231 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2233 /* Skip this entry */
2234 NextEntry
= NextEntry
->Flink
;
2238 /* Calculate the size we'll need and allocate a copy */
2239 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2240 LdrEntry
->BaseDllName
.MaximumLength
+
2241 sizeof(UNICODE_NULL
);
2242 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2243 if (!NewEntry
) return FALSE
;
2245 /* Copy the entry over */
2246 *NewEntry
= *LdrEntry
;
2248 /* Allocate the name */
2249 NewEntry
->FullDllName
.Buffer
=
2250 ExAllocatePoolWithTag(PagedPool
,
2251 LdrEntry
->FullDllName
.MaximumLength
+
2252 sizeof(UNICODE_NULL
),
2254 if (!NewEntry
->FullDllName
.Buffer
)
2256 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2260 /* Set the base name */
2261 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2263 /* Copy the full and base name */
2264 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2265 LdrEntry
->FullDllName
.Buffer
,
2266 LdrEntry
->FullDllName
.MaximumLength
);
2267 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2268 LdrEntry
->BaseDllName
.Buffer
,
2269 LdrEntry
->BaseDllName
.MaximumLength
);
2271 /* Null-terminate the base name */
2272 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2273 sizeof(WCHAR
)] = UNICODE_NULL
;
2275 /* Insert the entry into the list */
2276 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2277 NextEntry
= NextEntry
->Flink
;
2280 /* Build the import lists for the boot drivers */
2281 MiBuildImportsForBootDrivers();
2289 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2290 IN OUT PVOID
*ImageBaseAddress
,
2291 IN PUNICODE_STRING BaseImageName
,
2292 IN BOOLEAN BootDriver
)
2294 PLIST_ENTRY NextEntry
;
2295 BOOLEAN DriverFound
= FALSE
;
2296 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2297 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2298 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2301 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2302 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2305 /* Make sure there's enough system PTEs for a large page driver */
2306 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2311 /* This happens if the registry key had a "*" (wildcard) in it */
2312 if (MiLargePageAllDrivers
== 0)
2314 /* It didn't, so scan the list */
2315 NextEntry
= MiLargePageDriverList
.Flink
;
2316 while (NextEntry
!= &MiLargePageDriverList
)
2318 /* Check if the driver name matches */
2319 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2320 MI_LARGE_PAGE_DRIVER_ENTRY
,
2322 if (RtlEqualUnicodeString(BaseImageName
,
2323 &LargePageDriverEntry
->BaseName
,
2326 /* Enable large pages for this driver */
2332 NextEntry
= NextEntry
->Flink
;
2335 /* If we didn't find the driver, it doesn't need large pages */
2336 if (DriverFound
== FALSE
) return FALSE
;
2339 /* Nothing to do yet */
2340 DPRINT1("Large pages not supported!\n");
2346 MiSetSystemCodeProtection(
2347 _In_ PMMPTE FirstPte
,
2348 _In_ PMMPTE LastPte
,
2349 _In_ ULONG Protection
)
2355 for (PointerPte
= FirstPte
; PointerPte
<= LastPte
; PointerPte
++)
2358 TempPte
= *PointerPte
;
2360 /* Make sure it's valid */
2361 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
2363 /* Update the protection */
2364 TempPte
.u
.Hard
.Write
= BooleanFlagOn(Protection
, IMAGE_SCN_MEM_WRITE
);
2365 #if _MI_HAS_NO_EXECUTE
2366 TempPte
.u
.Hard
.NoExecute
= !BooleanFlagOn(Protection
, IMAGE_SCN_MEM_EXECUTE
);
2369 MI_UPDATE_VALID_PTE(PointerPte
, TempPte
);
2373 KeFlushEntireTb(TRUE
, TRUE
);
2380 MiWriteProtectSystemImage(
2381 _In_ PVOID ImageBase
)
2383 PIMAGE_NT_HEADERS NtHeaders
;
2384 PIMAGE_SECTION_HEADER SectionHeaders
, Section
;
2386 PVOID SectionBase
, SectionEnd
;
2389 PMMPTE FirstPte
, LastPte
;
2391 /* Check if the registry setting is on or not */
2392 if (MmEnforceWriteProtection
== FALSE
)
2394 /* Ignore section protection */
2398 /* Large page mapped images are not supported */
2399 NT_ASSERT(!MI_IS_PHYSICAL_ADDRESS(ImageBase
));
2401 /* Session images are not yet supported */
2402 NT_ASSERT(!MI_IS_SESSION_ADDRESS(ImageBase
));
2404 /* Get the NT headers */
2405 NtHeaders
= RtlImageNtHeader(ImageBase
);
2406 if (NtHeaders
== NULL
)
2408 DPRINT1("Failed to get NT headers for image @ %p\n", ImageBase
);
2412 /* Don't touch NT4 drivers */
2413 if ((NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) ||
2414 (NtHeaders
->OptionalHeader
.MajorSubsystemVersion
< 5))
2416 DPRINT1("Skipping NT 4 driver @ %p\n", ImageBase
);
2420 /* Get the section headers */
2421 SectionHeaders
= IMAGE_FIRST_SECTION(NtHeaders
);
2423 /* Get the base address of the first section */
2424 SectionBase
= Add2Ptr(ImageBase
, SectionHeaders
[0].VirtualAddress
);
2426 /* Start protecting the image header as R/O */
2427 FirstPte
= MiAddressToPte(ImageBase
);
2428 LastPte
= MiAddressToPte(SectionBase
) - 1;
2429 Protection
= IMAGE_SCN_MEM_READ
;
2430 if (LastPte
>= FirstPte
)
2432 MiSetSystemCodeProtection(FirstPte
, LastPte
, IMAGE_SCN_MEM_READ
);
2435 /* Loop the sections */
2436 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
2438 /* Get the section base address and size */
2439 Section
= &SectionHeaders
[i
];
2440 SectionBase
= Add2Ptr(ImageBase
, Section
->VirtualAddress
);
2441 SectionSize
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2443 /* Get the first PTE of this section */
2444 FirstPte
= MiAddressToPte(SectionBase
);
2446 /* Check for overlap with the previous range */
2447 if (FirstPte
== LastPte
)
2449 /* Combine the old and new protection by ORing them */
2450 Protection
|= (Section
->Characteristics
& IMAGE_SCN_PROTECTION_MASK
);
2452 /* Update the protection for this PTE */
2453 MiSetSystemCodeProtection(FirstPte
, FirstPte
, Protection
);
2459 /* There can not be gaps! */
2460 NT_ASSERT(FirstPte
== (LastPte
+ 1));
2462 /* Get the end of the section and the last PTE */
2463 SectionEnd
= Add2Ptr(SectionBase
, SectionSize
- 1);
2464 NT_ASSERT(SectionEnd
< Add2Ptr(ImageBase
, NtHeaders
->OptionalHeader
.SizeOfImage
));
2465 LastPte
= MiAddressToPte(SectionEnd
);
2467 /* If there are no more pages (after an overlap), skip this section */
2468 if (LastPte
< FirstPte
)
2470 NT_ASSERT(FirstPte
== (LastPte
+ 1));
2474 /* Get the section protection */
2475 Protection
= (Section
->Characteristics
& IMAGE_SCN_PROTECTION_MASK
);
2477 /* Update the protection for this section */
2478 MiSetSystemCodeProtection(FirstPte
, LastPte
, Protection
);
2481 /* Image should end with the last section */
2482 if (ALIGN_UP_POINTER_BY(SectionEnd
, PAGE_SIZE
) !=
2483 Add2Ptr(ImageBase
, NtHeaders
->OptionalHeader
.SizeOfImage
))
2485 DPRINT1("ImageBase 0x%p ImageSize 0x%lx Section %u VA 0x%lx Raw 0x%lx virt 0x%lx\n",
2487 NtHeaders
->OptionalHeader
.SizeOfImage
,
2489 Section
->VirtualAddress
,
2490 Section
->SizeOfRawData
,
2491 Section
->Misc
.VirtualSize
);
2497 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2501 PETHREAD CurrentThread
= PsGetCurrentThread();
2502 PFN_COUNT PageCount
= 0;
2503 PFN_NUMBER PageFrameIndex
;
2507 /* The page fault handler is broken and doesn't page back in! */
2508 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
2511 /* Get the driver's base address */
2512 ImageBase
= MiPteToAddress(PointerPte
);
2513 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2515 /* If this is a large page, it's stuck in physical memory */
2516 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2518 /* Lock the working set */
2519 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2522 while (PointerPte
<= LastPte
)
2524 /* Check for valid PTE */
2525 if (PointerPte
->u
.Hard
.Valid
== 1)
2527 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2528 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2529 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2531 /* No working sets in ReactOS yet */
2535 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2539 /* Release the working set */
2540 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2542 /* Do we have any driver pages? */
2545 /* Update counters */
2546 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2552 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2554 ULONG_PTR ImageBase
;
2555 PIMAGE_NT_HEADERS NtHeaders
;
2556 ULONG Sections
, Alignment
, Size
;
2557 PIMAGE_SECTION_HEADER Section
;
2558 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2559 if (MmDisablePagingExecutive
) return;
2561 /* Get the driver base address and its NT header */
2562 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2563 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2564 if (!NtHeaders
) return;
2566 /* Get the sections and their alignment */
2567 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2568 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2570 /* Loop each section */
2571 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2574 /* Find PAGE or .edata */
2575 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2576 (*(PULONG
)Section
->Name
== 'ade.'))
2578 /* Had we already done some work? */
2581 /* Nope, setup the first PTE address */
2582 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2587 /* Compute the size */
2588 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2590 /* Find the last PTE that maps this section */
2591 LastPte
= MiAddressToPte(ImageBase
+
2592 Section
->VirtualAddress
+
2599 /* Had we found a section before? */
2602 /* Mark it as pageable */
2603 MiSetPagingOfDriver(PointerPte
, LastPte
);
2608 /* Keep searching */
2613 /* Handle the straggler */
2614 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2619 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2621 PIMAGE_NT_HEADERS NtHeader
;
2624 /* Get NT Headers */
2625 NtHeader
= RtlImageNtHeader(BaseAddress
);
2628 /* Check if this image is only safe for UP while we have 2+ CPUs */
2629 if ((KeNumberProcessors
> 1) &&
2630 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2637 /* Otherwise, it's safe */
2643 MmCheckSystemImage(IN HANDLE ImageHandle
,
2644 IN BOOLEAN PurgeSection
)
2647 HANDLE SectionHandle
;
2648 PVOID ViewBase
= NULL
;
2649 SIZE_T ViewSize
= 0;
2650 IO_STATUS_BLOCK IoStatusBlock
;
2651 FILE_STANDARD_INFORMATION FileStandardInfo
;
2652 KAPC_STATE ApcState
;
2653 PIMAGE_NT_HEADERS NtHeaders
;
2654 OBJECT_ATTRIBUTES ObjectAttributes
;
2657 /* Setup the object attributes */
2658 InitializeObjectAttributes(&ObjectAttributes
,
2660 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2664 /* Create a section for the DLL */
2665 Status
= ZwCreateSection(&SectionHandle
,
2666 SECTION_MAP_EXECUTE
,
2672 if (!NT_SUCCESS(Status
))
2674 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2678 /* Make sure we're in the system process */
2679 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2682 Status
= ZwMapViewOfSection(SectionHandle
,
2692 if (!NT_SUCCESS(Status
))
2694 /* We failed, close the handle and return */
2695 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2696 KeUnstackDetachProcess(&ApcState
);
2697 ZwClose(SectionHandle
);
2701 /* Now query image information */
2702 Status
= ZwQueryInformationFile(ImageHandle
,
2705 sizeof(FileStandardInfo
),
2706 FileStandardInformation
);
2707 if (NT_SUCCESS(Status
))
2709 /* First, verify the checksum */
2710 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2715 /* Set checksum failure */
2716 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2720 /* Make sure it's a real image */
2721 NtHeaders
= RtlImageNtHeader(ViewBase
);
2724 /* Set checksum failure */
2725 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2729 /* Make sure it's for the correct architecture */
2730 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2731 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2733 /* Set protection failure */
2734 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2738 /* Check that it's a valid SMP image if we have more then one CPU */
2739 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2741 /* Otherwise it's not the right image */
2742 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2746 /* Unmap the section, close the handle, and return status */
2748 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2749 KeUnstackDetachProcess(&ApcState
);
2750 ZwClose(SectionHandle
);
2756 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2757 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2758 IN PUNICODE_STRING LoadedName OPTIONAL
,
2760 OUT PVOID
*ModuleObject
,
2761 OUT PVOID
*ImageBaseAddress
)
2763 PVOID ModuleLoadBase
= NULL
;
2765 HANDLE FileHandle
= NULL
;
2766 OBJECT_ATTRIBUTES ObjectAttributes
;
2767 IO_STATUS_BLOCK IoStatusBlock
;
2768 PIMAGE_NT_HEADERS NtHeader
;
2769 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2770 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2771 ULONG EntrySize
, DriverSize
;
2772 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2773 PCHAR MissingApiName
, Buffer
;
2774 PWCHAR MissingDriverName
;
2775 HANDLE SectionHandle
;
2776 ACCESS_MASK DesiredAccess
;
2777 PVOID Section
= NULL
;
2778 BOOLEAN LockOwned
= FALSE
;
2779 PLIST_ENTRY NextEntry
;
2780 IMAGE_INFO ImageInfo
;
2784 /* Detect session-load */
2788 ASSERT(NamePrefix
== NULL
);
2789 ASSERT(LoadedName
== NULL
);
2791 /* Make sure the process is in session too */
2792 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2795 /* Allocate a buffer we'll use for names */
2796 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
2797 MAXIMUM_FILENAME_LENGTH
,
2799 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2801 /* Check for a separator */
2802 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2807 /* Loop the path until we get to the base name */
2808 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2809 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2811 /* Get the length */
2812 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2813 BaseLength
*= sizeof(WCHAR
);
2815 /* Setup the string */
2816 BaseName
.Length
= (USHORT
)BaseLength
;
2817 BaseName
.Buffer
= p
;
2821 /* Otherwise, we already have a base name */
2822 BaseName
.Length
= FileName
->Length
;
2823 BaseName
.Buffer
= FileName
->Buffer
;
2826 /* Setup the maximum length */
2827 BaseName
.MaximumLength
= BaseName
.Length
;
2829 /* Now compute the base directory */
2830 BaseDirectory
= *FileName
;
2831 BaseDirectory
.Length
-= BaseName
.Length
;
2832 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2834 /* And the prefix, which for now is just the name itself */
2835 PrefixName
= *FileName
;
2837 /* Check if we have a prefix */
2838 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2840 /* Check if we already have a name, use it instead */
2841 if (LoadedName
) BaseName
= *LoadedName
;
2843 /* Check for loader snap debugging */
2844 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2846 /* Print out standard string */
2847 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2848 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2851 /* Acquire the load lock */
2853 ASSERT(LockOwned
== FALSE
);
2855 KeEnterCriticalRegion();
2856 KeWaitForSingleObject(&MmSystemLoadLock
,
2862 /* Scan the module list */
2863 NextEntry
= PsLoadedModuleList
.Flink
;
2864 while (NextEntry
!= &PsLoadedModuleList
)
2866 /* Get the entry and compare the names */
2867 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2868 LDR_DATA_TABLE_ENTRY
,
2870 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2872 /* Found it, break out */
2877 NextEntry
= NextEntry
->Flink
;
2880 /* Check if we found the image */
2881 if (NextEntry
!= &PsLoadedModuleList
)
2883 /* Check if we had already mapped a section */
2886 /* Dereference and clear */
2887 ObDereferenceObject(Section
);
2891 /* Check if this was supposed to be a session load */
2894 /* It wasn't, so just return the data */
2895 *ModuleObject
= LdrEntry
;
2896 *ImageBaseAddress
= LdrEntry
->DllBase
;
2897 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2901 /* We don't support session loading yet */
2902 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
2903 Status
= STATUS_NOT_IMPLEMENTED
;
2911 /* It wasn't loaded, and we didn't have a previous attempt */
2912 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2913 KeLeaveCriticalRegion();
2916 /* Check if KD is enabled */
2917 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2919 /* FIXME: Attempt to get image from KD */
2922 /* We don't have a valid entry */
2925 /* Setup image attributes */
2926 InitializeObjectAttributes(&ObjectAttributes
,
2928 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2932 /* Open the image */
2933 Status
= ZwOpenFile(&FileHandle
,
2937 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2939 if (!NT_SUCCESS(Status
))
2941 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
2947 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2948 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2949 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2950 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2956 /* Check if this is a session-load */
2959 /* Then we only need read and execute */
2960 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2964 /* Otherwise, we can allow write access */
2965 DesiredAccess
= SECTION_ALL_ACCESS
;
2968 /* Initialize the attributes for the section */
2969 InitializeObjectAttributes(&ObjectAttributes
,
2971 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2975 /* Create the section */
2976 Status
= ZwCreateSection(&SectionHandle
,
2983 if (!NT_SUCCESS(Status
))
2985 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2989 /* Now get the section pointer */
2990 Status
= ObReferenceObjectByHandle(SectionHandle
,
2991 SECTION_MAP_EXECUTE
,
2992 MmSectionObjectType
,
2996 ZwClose(SectionHandle
);
2997 if (!NT_SUCCESS(Status
)) goto Quickie
;
2999 /* Check if this was supposed to be a session-load */
3002 /* We don't support session loading yet */
3003 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3007 /* Check the loader list again, we should end up in the path below */
3012 /* We don't have a valid entry */
3016 /* Load the image */
3017 Status
= MiLoadImageSection(&Section
,
3022 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3024 /* Get the size of the driver */
3025 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageInformation
.ImageFileSize
;
3027 /* Make sure we're not being loaded into session space */
3030 /* Check for success */
3031 if (NT_SUCCESS(Status
))
3033 /* Support large pages for drivers */
3034 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3040 /* Dereference the section */
3041 ObDereferenceObject(Section
);
3045 /* Check for failure of the load earlier */
3046 if (!NT_SUCCESS(Status
))
3048 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3052 /* Relocate the driver */
3053 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3057 STATUS_CONFLICTING_ADDRESSES
,
3058 STATUS_INVALID_IMAGE_FORMAT
);
3059 if (!NT_SUCCESS(Status
))
3061 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3065 /* Get the NT Header */
3066 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3068 /* Calculate the size we'll need for the entry and allocate it */
3069 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3071 sizeof(UNICODE_NULL
);
3073 /* Allocate the entry */
3074 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3078 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3082 /* Setup the entry */
3083 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3084 LdrEntry
->LoadCount
= 1;
3085 LdrEntry
->LoadedImports
= LoadedImports
;
3086 LdrEntry
->PatchInformation
= NULL
;
3088 /* Check the version */
3089 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3090 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3092 /* Mark this image as a native image */
3093 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3096 /* Setup the rest of the entry */
3097 LdrEntry
->DllBase
= ModuleLoadBase
;
3098 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3099 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3100 LdrEntry
->SizeOfImage
= DriverSize
;
3101 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3102 LdrEntry
->SectionPointer
= Section
;
3104 /* Now write the DLL name */
3105 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3106 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3107 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3109 /* Copy and null-terminate it */
3110 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3113 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3115 /* Now allocate the full name */
3116 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3118 sizeof(UNICODE_NULL
),
3120 if (!LdrEntry
->FullDllName
.Buffer
)
3122 /* Don't fail, just set it to zero */
3123 LdrEntry
->FullDllName
.Length
= 0;
3124 LdrEntry
->FullDllName
.MaximumLength
= 0;
3129 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3130 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3132 /* Copy and null-terminate */
3133 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3136 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3140 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3142 /* Resolve imports */
3143 MissingApiName
= Buffer
;
3144 MissingDriverName
= NULL
;
3145 Status
= MiResolveImageReferences(ModuleLoadBase
,
3151 if (!NT_SUCCESS(Status
))
3153 BOOLEAN NeedToFreeString
= FALSE
;
3155 /* If the lowest bit is set to 1, this is a hint that we need to free */
3156 if (*(ULONG_PTR
*)&MissingDriverName
& 1)
3158 NeedToFreeString
= TRUE
;
3159 *(ULONG_PTR
*)&MissingDriverName
&= ~1;
3162 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3163 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3164 MissingDriverName
, MissingApiName
);
3166 if (NeedToFreeString
)
3168 ExFreePoolWithTag(MissingDriverName
, TAG_LDR_WSTR
);
3172 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3174 /* Check if we need to free the name */
3175 if (LdrEntry
->FullDllName
.Buffer
)
3178 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3181 /* Free the entry itself */
3182 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3187 /* Update the loader entry */
3188 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3189 LDRP_ENTRY_PROCESSED
|
3191 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3192 LdrEntry
->LoadedImports
= LoadedImports
;
3194 /* FIXME: Call driver verifier's loader function */
3196 /* Write-protect the system image */
3197 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3199 /* Check if notifications are enabled */
3200 if (PsImageNotifyEnabled
)
3202 /* Fill out the notification data */
3203 ImageInfo
.Properties
= 0;
3204 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3205 ImageInfo
.SystemModeImage
= TRUE
;
3206 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3207 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3208 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3210 /* Send the notification */
3211 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3214 #if defined(KDBG) || defined(_WINKD_)
3215 /* MiCacheImageSymbols doesn't detect rossym */
3218 /* Check if there's symbols */
3219 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3222 /* Check if the system root is present */
3223 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3224 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3226 /* Add the system root */
3227 UnicodeTemp
= PrefixName
;
3228 UnicodeTemp
.Buffer
+= 11;
3229 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3232 &SharedUserData
->NtSystemRoot
[2],
3237 /* Build the name */
3238 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3241 /* Setup the ansi string */
3242 RtlInitString(&AnsiTemp
, Buffer
);
3244 /* Notify the debugger */
3245 DbgLoadImageSymbols(&AnsiTemp
,
3247 (ULONG_PTR
)PsGetCurrentProcessId());
3248 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3251 /* Page the driver */
3252 ASSERT(Section
== NULL
);
3253 MiEnablePagingOfDriver(LdrEntry
);
3255 /* Return pointers */
3256 *ModuleObject
= LdrEntry
;
3257 *ImageBaseAddress
= LdrEntry
->DllBase
;
3260 /* Check if we have the lock acquired */
3263 /* Release the lock */
3264 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3265 KeLeaveCriticalRegion();
3269 /* If we have a file handle, close it */
3270 if (FileHandle
) ZwClose(FileHandle
);
3272 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3273 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3275 /* Free the name buffer and return status */
3276 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3280 PLDR_DATA_TABLE_ENTRY
3282 MiLookupDataTableEntry(IN PVOID Address
)
3284 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3285 PLIST_ENTRY NextEntry
;
3289 NextEntry
= PsLoadedModuleList
.Flink
;
3292 /* Get the loader entry */
3293 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3294 LDR_DATA_TABLE_ENTRY
,
3297 /* Check if the address matches */
3298 if ((Address
>= LdrEntry
->DllBase
) &&
3299 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3300 LdrEntry
->SizeOfImage
)))
3303 FoundEntry
= LdrEntry
;
3308 NextEntry
= NextEntry
->Flink
;
3309 } while(NextEntry
!= &PsLoadedModuleList
);
3311 /* Return the entry */
3315 /* PUBLIC FUNCTIONS ***********************************************************/
3322 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3324 PMMPTE StartPte
, EndPte
;
3325 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3328 /* Get the loader entry */
3329 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3330 if (!LdrEntry
) return NULL
;
3332 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3333 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3335 /* Don't do anything, just return the base address */
3336 return LdrEntry
->DllBase
;
3339 /* Wait for active DPCs to finish before we page out the driver */
3340 KeFlushQueuedDpcs();
3342 /* Get the PTE range for the whole driver image */
3343 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3344 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3346 /* Enable paging for the PTE range */
3347 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3348 MiSetPagingOfDriver(StartPte
, EndPte
);
3350 /* Return the base address */
3351 return LdrEntry
->DllBase
;
3359 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3369 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3371 PVOID ProcAddress
= NULL
;
3372 ANSI_STRING AnsiRoutineName
;
3374 PLIST_ENTRY NextEntry
;
3375 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3376 BOOLEAN Found
= FALSE
;
3377 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3378 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3381 /* Convert routine to ansi name */
3382 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3385 if (!NT_SUCCESS(Status
)) return NULL
;
3388 KeEnterCriticalRegion();
3389 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3391 /* Loop the loaded module list */
3392 NextEntry
= PsLoadedModuleList
.Flink
;
3393 while (NextEntry
!= &PsLoadedModuleList
)
3396 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3397 LDR_DATA_TABLE_ENTRY
,
3400 /* Check if it's the kernel or HAL */
3401 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3407 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3414 /* Check if we found a valid binary */
3417 /* Find the procedure name */
3418 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3421 /* Break out if we found it or if we already tried both modules */
3422 if (ProcAddress
) break;
3423 if (Modules
== 2) break;
3427 NextEntry
= NextEntry
->Flink
;
3430 /* Release the lock */
3431 ExReleaseResourceLite(&PsLoadedModuleResource
);
3432 KeLeaveCriticalRegion();
3434 /* Free the string and return */
3435 RtlFreeAnsiString(&AnsiRoutineName
);