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
;
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
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
181 /* Some debug stuff */
182 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE
);
184 if (FileName
->Buffer
)
188 pos
= wcsrchr(FileName
->Buffer
, '\\');
189 len
= wcslen(pos
) * sizeof(WCHAR
);
190 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
194 /* Loop the new driver PTEs */
195 TempPte
= ValidKernelPte
;
196 while (PointerPte
< LastPte
)
198 /* Make sure the PTE is not valid for whatever reason */
199 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
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 KeReleaseQueuedSpinLock(LockQueuePfnLock
, 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
)LdrEntry
->LoadedImports
& 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
)));
564 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
569 /* Acquire module list lock */
570 KeEnterCriticalRegion();
571 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
573 /* Acquire the spinlock too as we will insert or remove the entry */
574 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
576 /* Insert or remove from the list */
578 InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
);
580 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
583 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
584 ExReleaseResourceLite(&PsLoadedModuleResource
);
585 KeLeaveCriticalRegion();
591 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
596 ULONG_PTR OldBaseTop
, Delta
;
597 PLDR_DATA_TABLE_ENTRY LdrEntry
;
598 PLIST_ENTRY NextEntry
;
601 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
602 // since a real version of Windows would fail at this point, but they seem
603 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
604 // a feature which isn't even used by Windows. Priorities, priorities...
605 // Please note that Microsoft WDK EULA and license prohibits using
606 // the information contained within it for the generation of "non-Windows"
607 // drivers, which is precisely what LD will generate, since an LD driver
608 // will not load on Windows.
610 #ifdef _WORKING_LINKER_
613 PULONG_PTR ImageThunk
;
614 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
616 /* Calculate the top and delta */
617 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
618 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
620 /* Loop the loader block */
621 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
622 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
623 NextEntry
= NextEntry
->Flink
)
625 /* Get the loader entry */
626 LdrEntry
= CONTAINING_RECORD(NextEntry
,
627 LDR_DATA_TABLE_ENTRY
,
629 #ifdef _WORKING_LINKER_
631 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
633 IMAGE_DIRECTORY_ENTRY_IAT
,
635 if (!ImageThunk
) continue;
637 /* Make sure we have an IAT */
638 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
639 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
641 /* Check if it's within this module */
642 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
645 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
646 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
647 *ImageThunk
+= Delta
;
651 /* Get the import table */
652 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
654 IMAGE_DIRECTORY_ENTRY_IMPORT
,
656 if (!ImportDescriptor
) continue;
658 /* Make sure we have an IAT */
659 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
660 while ((ImportDescriptor
->Name
) &&
661 (ImportDescriptor
->OriginalFirstThunk
))
663 /* Get the image thunk */
664 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
665 ImportDescriptor
->FirstThunk
);
668 /* Check if it's within this module */
669 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
672 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
673 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
674 *ImageThunk
+= Delta
;
677 /* Go to the next thunk */
681 /* Go to the next import */
690 MiSnapThunk(IN PVOID DllBase
,
692 IN PIMAGE_THUNK_DATA Name
,
693 IN PIMAGE_THUNK_DATA Address
,
694 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
696 IN BOOLEAN SnapForwarder
,
697 OUT PCHAR
*MissingApi
)
702 PUSHORT OrdinalTable
;
703 PIMAGE_IMPORT_BY_NAME NameImport
;
705 ULONG Low
= 0, Mid
= 0, High
;
708 PCHAR MissingForwarder
;
709 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
712 UNICODE_STRING ForwarderName
;
713 PLIST_ENTRY NextEntry
;
714 PLDR_DATA_TABLE_ENTRY LdrEntry
;
715 ULONG ForwardExportSize
;
716 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
717 PIMAGE_IMPORT_BY_NAME ForwardName
;
718 SIZE_T ForwardLength
;
719 IMAGE_THUNK_DATA ForwardThunk
;
722 /* Check if this is an ordinal */
723 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
724 if ((IsOrdinal
) && !(SnapForwarder
))
726 /* Get the ordinal number and set it as missing */
727 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
728 ExportDirectory
->Base
);
729 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
733 /* Get the VA if we don't have to snap */
734 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
735 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
737 /* Copy the procedure name */
738 RtlStringCbCopyA(*MissingApi
,
739 MAXIMUM_FILENAME_LENGTH
,
740 (PCHAR
)&NameImport
->Name
[0]);
742 /* Setup name tables */
743 DPRINT("Import name: %s\n", NameImport
->Name
);
744 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
745 ExportDirectory
->AddressOfNames
);
746 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
747 ExportDirectory
->AddressOfNameOrdinals
);
749 /* Get the hint and check if it's valid */
750 Hint
= NameImport
->Hint
;
751 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
752 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
754 /* We have a match, get the ordinal number from here */
755 Ordinal
= OrdinalTable
[Hint
];
759 /* Do a binary search */
760 High
= ExportDirectory
->NumberOfNames
- 1;
763 /* Get new middle value */
764 Mid
= (Low
+ High
) >> 1;
767 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
785 /* Check if we couldn't find it */
788 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
789 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
792 /* Otherwise, this is the ordinal */
793 Ordinal
= OrdinalTable
[Mid
];
797 /* Check if the ordinal is invalid */
798 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
801 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
805 /* In case the forwarder is missing */
806 MissingForwarder
= NameBuffer
;
808 /* Resolve the address and write it */
809 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
810 ExportDirectory
->AddressOfFunctions
);
811 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
813 /* Assume success from now on */
814 Status
= STATUS_SUCCESS
;
816 /* Check if the function is actually a forwarder */
817 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
818 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
820 /* Now assume failure in case the forwarder doesn't exist */
821 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
823 /* Build the forwarder name */
824 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
825 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
828 DllName
.MaximumLength
= DllName
.Length
;
831 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
835 /* We failed, just return an error */
839 /* Loop the module list */
840 NextEntry
= PsLoadedModuleList
.Flink
;
841 while (NextEntry
!= &PsLoadedModuleList
)
843 /* Get the loader entry */
844 LdrEntry
= CONTAINING_RECORD(NextEntry
,
845 LDR_DATA_TABLE_ENTRY
,
848 /* Check if it matches */
849 if (RtlPrefixUnicodeString(&ForwarderName
,
850 &LdrEntry
->BaseDllName
,
853 /* Get the forwarder export directory */
854 ForwardExportDirectory
=
855 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
857 IMAGE_DIRECTORY_ENTRY_EXPORT
,
859 if (!ForwardExportDirectory
) break;
861 /* Allocate a name entry */
862 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
864 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
865 sizeof(*ForwardName
) +
868 if (!ForwardName
) break;
871 RtlCopyMemory(&ForwardName
->Name
[0],
872 DllName
.Buffer
+ DllName
.Length
,
874 ForwardName
->Hint
= 0;
876 /* Set the new address */
877 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
879 /* Snap the forwarder */
880 Status
= MiSnapThunk(LdrEntry
->DllBase
,
884 ForwardExportDirectory
,
889 /* Free the forwarder name and set the thunk */
890 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
891 Address
->u1
= ForwardThunk
.u1
;
895 /* Go to the next entry */
896 NextEntry
= NextEntry
->Flink
;
900 RtlFreeUnicodeString(&ForwarderName
);
910 MmUnloadSystemImage(IN PVOID ImageHandle
)
912 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
913 PVOID BaseAddress
= LdrEntry
->DllBase
;
916 BOOLEAN HadEntry
= FALSE
;
918 /* Acquire the loader lock */
919 KeEnterCriticalRegion();
920 KeWaitForSingleObject(&MmSystemLoadLock
,
926 /* Check if this driver was loaded at boot and didn't get imports parsed */
927 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
929 /* We should still be alive */
930 ASSERT(LdrEntry
->LoadCount
!= 0);
931 LdrEntry
->LoadCount
--;
933 /* Check if we're still loaded */
934 if (LdrEntry
->LoadCount
) goto Done
;
936 /* We should cleanup... are symbols loaded */
937 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
939 /* Create the ANSI name */
940 Status
= RtlUnicodeStringToAnsiString(&TempName
,
941 &LdrEntry
->BaseDllName
,
943 if (NT_SUCCESS(Status
))
945 /* Unload the symbols */
946 DbgUnLoadImageSymbols(&TempName
,
948 (ULONG_PTR
)PsGetCurrentProcessId());
949 RtlFreeAnsiString(&TempName
);
953 /* FIXME: Free the driver */
954 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
955 //MmFreeSection(LdrEntry->DllBase);
957 /* Check if we're linked in */
958 if (LdrEntry
->InLoadOrderLinks
.Flink
)
961 MiProcessLoaderEntry(LdrEntry
, FALSE
);
965 /* Dereference and clear the imports */
966 MiDereferenceImports(LdrEntry
->LoadedImports
);
967 MiClearImports(LdrEntry
);
969 /* Check if the entry needs to go away */
972 /* Check if it had a name */
973 if (LdrEntry
->FullDllName
.Buffer
)
976 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
979 /* Check if we had a section */
980 if (LdrEntry
->SectionPointer
)
983 ObDereferenceObject(LdrEntry
->SectionPointer
);
987 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
990 /* Release the system lock and return */
992 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
993 KeLeaveCriticalRegion();
994 return STATUS_SUCCESS
;
999 MiResolveImageReferences(IN PVOID ImageBase
,
1000 IN PUNICODE_STRING ImageFileDirectory
,
1001 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1002 OUT PCHAR
*MissingApi
,
1003 OUT PWCHAR
*MissingDriver
,
1004 OUT PLOAD_IMPORTS
*LoadImports
)
1006 static UNICODE_STRING DriversFolderName
= RTL_CONSTANT_STRING(L
"drivers\\");
1007 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
1008 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
1009 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
1010 PLOAD_IMPORTS LoadedImports
, NewImports
;
1011 ULONG GdiLink
, NormalLink
, i
;
1012 BOOLEAN ReferenceNeeded
, Loaded
;
1013 ANSI_STRING TempString
;
1014 UNICODE_STRING NameString
, DllName
;
1015 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
1016 PVOID ImportBase
, DllBase
;
1017 PLIST_ENTRY NextEntry
;
1018 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1020 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1022 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1023 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1025 /* No name string buffer yet */
1026 NameString
.Buffer
= NULL
;
1028 /* Assume no imports */
1029 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1031 /* Get the import descriptor */
1032 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1034 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1036 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1038 /* Loop all imports to count them */
1039 for (CurrentImport
= ImportDescriptor
;
1040 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1047 /* Make sure we have non-zero imports */
1050 /* Calculate and allocate the list we'll need */
1051 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1052 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1058 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1059 LoadedImports
->Count
= ImportCount
;
1065 LoadedImports
= NULL
;
1068 /* Reset the import count and loop descriptors again */
1069 ImportCount
= GdiLink
= NormalLink
= 0;
1070 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1073 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1075 /* Check if this is a GDI driver */
1077 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1079 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1080 NormalLink
= NormalLink
|
1081 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1082 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1083 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1084 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1086 /* Check if this is a valid GDI driver */
1087 if ((GdiLink
) && (NormalLink
))
1089 /* It's not, it's importing stuff it shouldn't be! */
1090 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1094 /* Check for user-mode printer or video card drivers, which don't belong */
1095 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1096 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1097 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1098 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1099 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1100 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1102 /* This is not kernel code */
1103 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1107 /* Check if this is a "core" import, which doesn't get referenced */
1108 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1109 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1110 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1112 /* Don't reference this */
1113 ReferenceNeeded
= FALSE
;
1117 /* Reference these modules */
1118 ReferenceNeeded
= TRUE
;
1121 /* Now setup a unicode string for the import */
1122 RtlInitAnsiString(&TempString
, ImportName
);
1123 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1124 if (!NT_SUCCESS(Status
))
1130 /* We don't support name prefixes yet */
1131 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1133 /* Remember that we haven't loaded the import at this point */
1138 /* Loop the driver list */
1139 NextEntry
= PsLoadedModuleList
.Flink
;
1140 while (NextEntry
!= &PsLoadedModuleList
)
1142 /* Get the loader entry and compare the name */
1143 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1144 LDR_DATA_TABLE_ENTRY
,
1146 if (RtlEqualUnicodeString(&NameString
,
1147 &LdrEntry
->BaseDllName
,
1150 /* Get the base address */
1151 ImportBase
= LdrEntry
->DllBase
;
1153 /* Check if we haven't loaded yet, and we need references */
1154 if (!(Loaded
) && (ReferenceNeeded
))
1156 /* Make sure we're not already loading */
1157 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1159 /* Increase the load count */
1160 LdrEntry
->LoadCount
++;
1164 /* Done, break out */
1168 /* Go to the next entry */
1169 NextEntry
= NextEntry
->Flink
;
1172 /* Check if we haven't loaded the import yet */
1175 /* Setup the import DLL name */
1176 DllName
.MaximumLength
= NameString
.Length
+
1177 ImageFileDirectory
->Length
+
1178 sizeof(UNICODE_NULL
);
1179 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1180 DllName
.MaximumLength
,
1182 if (!DllName
.Buffer
)
1184 /* We're out of resources */
1185 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1189 /* Add the import name to the base directory */
1190 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1191 RtlAppendUnicodeStringToString(&DllName
,
1194 /* Load the image */
1195 Status
= MmLoadSystemImage(&DllName
,
1202 /* win32k / GDI drivers can also import from system32 folder */
1203 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) &&
1204 (MI_IS_SESSION_ADDRESS(ImageBase
) || 1)) // HACK
1206 /* Free the old name buffer */
1207 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1209 /* Calculate size for a string the adds 'drivers\' */
1210 DllName
.MaximumLength
+= DriversFolderName
.Length
;
1212 /* Allocate the new buffer */
1213 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1214 DllName
.MaximumLength
,
1216 if (!DllName
.Buffer
)
1218 /* We're out of resources */
1219 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1223 /* Copy image directory and append 'drivers\' folder name */
1224 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1225 RtlAppendUnicodeStringToString(&DllName
, &DriversFolderName
);
1227 /* Now add the import name */
1228 RtlAppendUnicodeStringToString(&DllName
, &NameString
);
1230 /* Try once again to load the image */
1231 Status
= MmLoadSystemImage(&DllName
,
1239 if (!NT_SUCCESS(Status
))
1241 /* Fill out the information for the error */
1242 *MissingDriver
= DllName
.Buffer
;
1243 *(PULONG
)MissingDriver
|= 1;
1246 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1248 /* Don't free the name */
1249 DllName
.Buffer
= NULL
;
1251 /* Cleanup and return */
1255 /* We can free the DLL Name */
1256 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1257 DllName
.Buffer
= NULL
;
1259 /* We're now loaded */
1263 ASSERT(DllBase
== DllEntry
->DllBase
);
1265 /* Call the initialization routines */
1266 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1267 if (!NT_SUCCESS(Status
))
1269 /* We failed, unload the image */
1270 MmUnloadSystemImage(DllEntry
);
1271 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status
);
1275 /* Loop again to make sure that everything is OK */
1279 /* Check if we're support to reference this import */
1280 if ((ReferenceNeeded
) && (LoadedImports
))
1282 /* Make sure we're not already loading */
1283 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1286 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1291 /* Free the import name */
1292 RtlFreeUnicodeString(&NameString
);
1294 /* Set the missing driver name and get the export directory */
1295 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1296 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1298 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1300 if (!ExportDirectory
)
1302 /* Cleanup and return */
1303 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1304 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1308 /* Make sure we have an IAT */
1309 if (ImportDescriptor
->OriginalFirstThunk
)
1311 /* Get the first thunks */
1312 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1313 ImportDescriptor
->OriginalFirstThunk
);
1314 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1315 ImportDescriptor
->FirstThunk
);
1318 while (OrigThunk
->u1
.AddressOfData
)
1321 Status
= MiSnapThunk(ImportBase
,
1329 if (!NT_SUCCESS(Status
))
1331 /* Cleanup and return */
1335 /* Reset the buffer */
1336 *MissingApi
= MissingApiBuffer
;
1340 /* Go to the next import */
1344 /* Check if we have an import list */
1347 /* Reset the count again, and loop entries */
1349 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1351 if (LoadedImports
->Entry
[i
])
1353 /* Got an entry, OR it with 1 in case it's the single entry */
1354 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1355 MM_SYSLDR_SINGLE_ENTRY
);
1360 /* Check if we had no imports */
1363 /* Free the list and set it to no imports */
1364 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1365 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1367 else if (ImportCount
== 1)
1369 /* Just one entry, we can free the table and only use our entry */
1370 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1371 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1373 else if (ImportCount
!= LoadedImports
->Count
)
1375 /* Allocate a new list */
1376 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1377 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1383 NewImports
->Count
= 0;
1385 /* Loop all the imports */
1386 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1388 /* Make sure it's valid */
1389 if (LoadedImports
->Entry
[i
])
1392 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1393 NewImports
->Count
++;
1397 /* Free the old copy */
1398 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1399 LoadedImports
= NewImports
;
1403 /* Return the list */
1404 *LoadImports
= LoadedImports
;
1407 /* Return success */
1408 return STATUS_SUCCESS
;
1412 /* Cleanup and return */
1413 RtlFreeUnicodeString(&NameString
);
1417 MiDereferenceImports(LoadedImports
);
1418 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1426 MiFreeInitializationCode(IN PVOID InitStart
,
1430 PFN_NUMBER PagesFreed
;
1432 /* Get the start PTE */
1433 PointerPte
= MiAddressToPte(InitStart
);
1434 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1436 /* Compute the number of pages we expect to free */
1437 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
+ 1);
1439 /* Try to actually free them */
1440 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1449 MiFindInitializationCode(OUT PVOID
*StartVa
,
1452 ULONG Size
, SectionCount
, Alignment
;
1453 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1454 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1455 PLIST_ENTRY NextEntry
;
1456 PIMAGE_NT_HEADERS NtHeader
;
1457 PIMAGE_SECTION_HEADER Section
, LastSection
;
1460 /* So we don't free our own code yet */
1461 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1463 /* Assume failure */
1466 /* Enter a critical region while we loop the list */
1467 KeEnterCriticalRegion();
1469 /* Loop all loaded modules */
1470 NextEntry
= PsLoadedModuleList
.Flink
;
1471 while (NextEntry
!= &PsLoadedModuleList
)
1473 /* Get the loader entry and its DLL base */
1474 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1475 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1477 /* Only process boot loaded images. Other drivers are processed by
1478 MmFreeDriverInitialization */
1479 if (LdrEntry
->Flags
& LDRP_MM_LOADED
)
1482 NextEntry
= NextEntry
->Flink
;
1486 /* Get the NT header */
1487 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1491 NextEntry
= NextEntry
->Flink
;
1495 /* Get the first section, the section count, and scan them all */
1496 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1497 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1499 while (SectionCount
> 0)
1501 /* Assume failure */
1504 /* Is this the INIT section or a discardable section? */
1505 if ((*(PULONG
)Section
->Name
== 'TINI') ||
1506 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1514 /* Pick the biggest size -- either raw or virtual */
1515 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1517 /* Read the section alignment */
1518 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1520 /* Align the start and end addresses appropriately */
1521 InitStart
= DllBase
+ Section
->VirtualAddress
;
1522 InitEnd
= ((Alignment
+ InitStart
+ Size
- 2) & 0xFFFFF000) - 1;
1523 InitStart
= (InitStart
+ (PAGE_SIZE
- 1)) & 0xFFFFF000;
1525 /* Have we reached the last section? */
1526 if (SectionCount
== 1)
1529 LastSection
= Section
;
1533 /* We have not, loop all the sections */
1537 /* Keep going until we find a non-discardable section range */
1540 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1542 /* Discardable, so record it, then keep going */
1543 LastSection
= Section
;
1547 /* Non-contigous discard flag, or no flag, break out */
1551 while (SectionCount
> 1);
1554 /* Have we found a discardable or init section? */
1557 /* Pick the biggest size -- either raw or virtual */
1558 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1560 /* Use this as the end of the section address */
1561 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
- 1;
1563 /* Have we reached the last section yet? */
1564 if (SectionCount
!= 1)
1566 /* Then align this accross the session boundary */
1567 InitEnd
= ((Alignment
+ InitEnd
- 1) & 0XFFFFF000) - 1;
1571 /* Make sure we don't let the init section go past the image */
1572 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1573 if (InitEnd
> ImageEnd
) InitEnd
= (ImageEnd
- 1) | (PAGE_SIZE
- 1);
1575 /* Make sure we have a valid, non-zero init section */
1576 if (InitStart
<= InitEnd
)
1578 /* Make sure we are not within this code itself */
1579 if ((InitCode
>= InitStart
) && (InitCode
<= InitEnd
))
1581 /* Return it, we can't free ourselves now */
1582 ASSERT(*StartVa
== 0);
1583 *StartVa
= (PVOID
)InitStart
;
1584 *EndVa
= (PVOID
)InitEnd
;
1588 /* This isn't us -- go ahead and free it */
1589 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1590 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1595 /* Move to the next section */
1600 /* Move to the next module */
1601 NextEntry
= NextEntry
->Flink
;
1604 /* Leave the critical region and return */
1605 KeLeaveCriticalRegion();
1609 * Note: This function assumes that all discardable sections are at the end of
1610 * the PE file. It searches backwards until it finds the non-discardable section
1614 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1616 PMMPTE StartPte
, EndPte
;
1617 PFN_NUMBER PageCount
;
1620 PIMAGE_NT_HEADERS NtHeader
;
1621 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1623 /* Get the base address and the page count */
1624 DllBase
= LdrEntry
->DllBase
;
1625 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1627 /* Get the last PTE in this image */
1628 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1630 /* Get the NT header */
1631 NtHeader
= RtlImageNtHeader(DllBase
);
1632 if (!NtHeader
) return;
1634 /* Get the last section and loop each section backwards */
1635 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1636 DiscardSection
= NULL
;
1637 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1639 /* Go back a section and check if it's discardable */
1641 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1643 /* It is, select it for freeing */
1644 DiscardSection
= Section
;
1648 /* No more discardable sections exist, bail out */
1653 /* Bail out if there's nothing to free */
1654 if (!DiscardSection
) return;
1656 /* Push the DLL base to the first disacrable section, and get its PTE */
1657 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1658 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1659 StartPte
= MiAddressToPte(DllBase
);
1661 /* Check how many pages to free total */
1662 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1663 if (!PageCount
) return;
1665 /* Delete this many PTEs */
1666 MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1672 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1674 PLIST_ENTRY NextEntry
;
1676 PIMAGE_NT_HEADERS NtHeader
;
1677 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1678 PIMAGE_FILE_HEADER FileHeader
;
1679 BOOLEAN ValidRelocs
;
1680 PIMAGE_DATA_DIRECTORY DataDirectory
;
1681 PVOID DllBase
, NewImageAddress
;
1683 PMMPTE PointerPte
, StartPte
, LastPte
;
1686 MMPTE TempPte
, OldPte
;
1688 /* Loop driver list */
1689 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1690 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1691 NextEntry
= NextEntry
->Flink
)
1693 /* Get the loader entry and NT header */
1694 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1695 LDR_DATA_TABLE_ENTRY
,
1697 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1700 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1702 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1703 &LdrEntry
->FullDllName
);
1705 /* Get the first PTE and the number of PTEs we'll need */
1706 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1707 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1708 LastPte
= StartPte
+ PteCount
;
1712 while (PointerPte
< LastPte
)
1715 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1716 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1717 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1718 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1722 /* Skip kernel and HAL */
1723 /* ROS HACK: Skip BOOTVID/KDCOM too */
1725 if (i
<= 4) continue;
1727 /* Skip non-drivers */
1728 if (!NtHeader
) continue;
1730 /* Get the file header and make sure we can relocate */
1731 FileHeader
= &NtHeader
->FileHeader
;
1732 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1733 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1734 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1736 /* Everything made sense until now, check the relocation section too */
1737 DataDirectory
= &NtHeader
->OptionalHeader
.
1738 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1739 if (!DataDirectory
->VirtualAddress
)
1741 /* We don't really have relocations */
1742 ValidRelocs
= FALSE
;
1746 /* Make sure the size is valid */
1747 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1748 LdrEntry
->SizeOfImage
)
1750 /* They're not, skip */
1754 /* We have relocations */
1758 /* Remember the original address */
1759 DllBase
= LdrEntry
->DllBase
;
1762 PointerPte
= StartPte
;
1763 while (PointerPte
< LastPte
)
1765 /* Mark the page modified in the PFN database */
1766 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1767 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1768 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1769 Pfn1
->u3
.e1
.Modified
= TRUE
;
1775 /* Now reserve system PTEs for the image */
1776 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1779 /* Shouldn't happen */
1780 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1784 /* This is the new virtual address for the module */
1785 LastPte
= PointerPte
+ PteCount
;
1786 NewImageAddress
= MiPteToAddress(PointerPte
);
1789 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1790 ASSERT(ExpInitializationPhase
== 0);
1792 /* Loop the new driver PTEs */
1793 TempPte
= ValidKernelPte
;
1794 while (PointerPte
< LastPte
)
1796 /* Copy the old data */
1798 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1800 /* Set page number from the loader's memory */
1801 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1804 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1811 /* Update position */
1812 PointerPte
-= PteCount
;
1815 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1817 /* Set the image base to the address where the loader put it */
1818 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1820 /* Check if we had relocations */
1823 /* Relocate the image */
1824 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1828 STATUS_CONFLICTING_ADDRESSES
,
1829 STATUS_INVALID_IMAGE_FORMAT
);
1830 if (!NT_SUCCESS(Status
))
1832 /* This shouldn't happen */
1833 ERROR_FATAL("Relocations failed!\n");
1838 /* Update the loader entry */
1839 LdrEntry
->DllBase
= NewImageAddress
;
1841 /* Update the thunks */
1842 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1843 MiUpdateThunks(LoaderBlock
,
1846 LdrEntry
->SizeOfImage
);
1848 /* Update the loader entry */
1849 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1850 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1851 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1852 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1854 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1861 MiBuildImportsForBootDrivers(VOID
)
1863 PLIST_ENTRY NextEntry
, NextEntry2
;
1864 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1865 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1866 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1867 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1868 PLOAD_IMPORTS LoadedImports
;
1869 ULONG LoadedImportsSize
, ImportSize
;
1870 PULONG_PTR ImageThunk
;
1871 ULONG_PTR DllBase
, DllEnd
;
1872 ULONG Modules
= 0, i
, j
= 0;
1873 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1875 /* Initialize variables */
1876 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1878 /* Loop the loaded module list... we are early enough that no lock is needed */
1879 NextEntry
= PsLoadedModuleList
.Flink
;
1880 while (NextEntry
!= &PsLoadedModuleList
)
1883 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1884 LDR_DATA_TABLE_ENTRY
,
1887 /* Check if it's the kernel or HAL */
1888 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1891 KernelEntry
= LdrEntry
;
1893 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1896 HalEntry
= LdrEntry
;
1899 /* Check if this is a driver DLL */
1900 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1902 /* Check if this is the HAL or kernel */
1903 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1905 /* Add a reference */
1906 LdrEntry
->LoadCount
= 1;
1910 /* No referencing needed */
1911 LdrEntry
->LoadCount
= 0;
1916 /* Add a reference for all other modules as well */
1917 LdrEntry
->LoadCount
= 1;
1920 /* Remember this came from the loader */
1921 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1924 NextEntry
= NextEntry
->Flink
;
1928 /* We must have at least found the kernel and HAL */
1929 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1931 /* Allocate the list */
1932 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1933 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1935 /* Loop the loaded module list again */
1936 NextEntry
= PsLoadedModuleList
.Flink
;
1937 while (NextEntry
!= &PsLoadedModuleList
)
1940 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1941 LDR_DATA_TABLE_ENTRY
,
1943 #ifdef _WORKING_LOADER_
1944 /* Get its imports */
1945 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1947 IMAGE_DIRECTORY_ENTRY_IAT
,
1951 /* Get its imports */
1952 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1954 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1956 if (!ImportDescriptor
)
1960 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1961 NextEntry
= NextEntry
->Flink
;
1965 /* Clear the list and count the number of IAT thunks */
1966 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1967 #ifdef _WORKING_LOADER_
1968 ImportSize
/= sizeof(ULONG_PTR
);
1970 /* Scan the thunks */
1971 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1973 DllBase
= DllEnd
= i
= 0;
1974 while ((ImportDescriptor
->Name
) &&
1975 (ImportDescriptor
->OriginalFirstThunk
))
1977 /* Get the image thunk */
1978 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1979 ImportDescriptor
->FirstThunk
);
1983 /* Do we already have an address? */
1986 /* Is the thunk in the same address? */
1987 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1989 /* Skip it, we already have a reference for it */
1990 ASSERT(EntryArray
[j
]);
1996 /* Loop the loaded module list to locate this address owner */
1998 NextEntry2
= PsLoadedModuleList
.Flink
;
1999 while (NextEntry2
!= &PsLoadedModuleList
)
2002 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
2003 LDR_DATA_TABLE_ENTRY
,
2006 /* Get the address range for this module */
2007 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
2008 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
2010 /* Check if this IAT entry matches it */
2011 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
2014 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
2015 EntryArray
[j
] = LdrEntry2
;
2019 /* Keep searching */
2020 NextEntry2
= NextEntry2
->Flink
;
2024 /* Do we have a thunk outside the range? */
2025 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
2030 /* Should not be happening */
2031 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2032 LdrEntry
, ImageThunk
, *ImageThunk
);
2035 /* Reset if we hit this */
2038 #ifndef _WORKING_LOADER_
2047 /* Now scan how many imports we really have */
2048 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
2050 /* Skip HAL and kernel */
2051 if ((EntryArray
[i
]) &&
2052 (EntryArray
[i
] != HalEntry
) &&
2053 (EntryArray
[i
] != KernelEntry
))
2055 /* A valid reference */
2056 LastEntry
= EntryArray
[i
];
2061 /* Do we have any imports after all? */
2065 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2067 else if (ImportSize
== 1)
2069 /* A single entry import */
2070 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2071 LastEntry
->LoadCount
++;
2075 /* We need an import table */
2076 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2077 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2080 ASSERT(LoadedImports
);
2082 /* Save the count */
2083 LoadedImports
->Count
= ImportSize
;
2085 /* Now copy all imports */
2086 for (i
= 0, j
= 0; i
< Modules
; i
++)
2088 /* Skip HAL and kernel */
2089 if ((EntryArray
[i
]) &&
2090 (EntryArray
[i
] != HalEntry
) &&
2091 (EntryArray
[i
] != KernelEntry
))
2093 /* A valid reference */
2094 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2095 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2096 EntryArray
[i
]->LoadCount
++;
2101 /* Should had as many entries as we expected */
2102 ASSERT(j
== ImportSize
);
2103 LdrEntry
->LoadedImports
= LoadedImports
;
2107 NextEntry
= NextEntry
->Flink
;
2110 /* Free the initial array */
2111 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2113 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2115 /* Kernel and HAL are loaded at boot */
2116 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2117 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2119 /* All worked well */
2120 return STATUS_SUCCESS
;
2126 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2129 PIMAGE_NT_HEADERS NtHeaders
;
2130 PIMAGE_SECTION_HEADER SectionHeader
;
2131 ULONG Sections
, Size
;
2133 /* Get the kernel section header */
2134 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2135 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2136 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2138 /* Loop all the sections */
2139 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2142 /* Grab the size of the section */
2143 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2145 /* Check for .RSRC section */
2146 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2148 /* Remember the PTEs so we can modify them later */
2149 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2150 SectionHeader
->VirtualAddress
);
2151 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2152 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2154 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2156 /* POOLCODE vs. POOLMI */
2157 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2159 /* Found Ex* Pool code */
2160 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2161 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2163 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2165 /* Found Mm* Pool code */
2166 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2167 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2170 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2171 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2173 /* Found MISYSPTE (Mm System PTE code)*/
2174 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2175 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2187 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2189 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2190 PLIST_ENTRY ListHead
, NextEntry
;
2193 /* Setup the loaded module list and locks */
2194 ExInitializeResourceLite(&PsLoadedModuleResource
);
2195 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2196 InitializeListHead(&PsLoadedModuleList
);
2198 /* Get loop variables and the kernel entry */
2199 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2200 NextEntry
= ListHead
->Flink
;
2201 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2202 LDR_DATA_TABLE_ENTRY
,
2204 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2206 /* Locate resource section, pool code, and system pte code */
2207 MiLocateKernelSections(LdrEntry
);
2209 /* Loop the loader block */
2210 while (NextEntry
!= ListHead
)
2212 /* Get the loader entry */
2213 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2214 LDR_DATA_TABLE_ENTRY
,
2217 /* FIXME: ROS HACK. Make sure this is a driver */
2218 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2220 /* Skip this entry */
2221 NextEntry
= NextEntry
->Flink
;
2225 /* Calculate the size we'll need and allocate a copy */
2226 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2227 LdrEntry
->BaseDllName
.MaximumLength
+
2228 sizeof(UNICODE_NULL
);
2229 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2230 if (!NewEntry
) return FALSE
;
2232 /* Copy the entry over */
2233 *NewEntry
= *LdrEntry
;
2235 /* Allocate the name */
2236 NewEntry
->FullDllName
.Buffer
=
2237 ExAllocatePoolWithTag(PagedPool
,
2238 LdrEntry
->FullDllName
.MaximumLength
+
2239 sizeof(UNICODE_NULL
),
2241 if (!NewEntry
->FullDllName
.Buffer
)
2243 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2247 /* Set the base name */
2248 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2250 /* Copy the full and base name */
2251 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2252 LdrEntry
->FullDllName
.Buffer
,
2253 LdrEntry
->FullDllName
.MaximumLength
);
2254 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2255 LdrEntry
->BaseDllName
.Buffer
,
2256 LdrEntry
->BaseDllName
.MaximumLength
);
2258 /* Null-terminate the base name */
2259 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2260 sizeof(WCHAR
)] = UNICODE_NULL
;
2262 /* Insert the entry into the list */
2263 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2264 NextEntry
= NextEntry
->Flink
;
2267 /* Build the import lists for the boot drivers */
2268 MiBuildImportsForBootDrivers();
2276 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2277 IN OUT PVOID
*ImageBaseAddress
,
2278 IN PUNICODE_STRING BaseImageName
,
2279 IN BOOLEAN BootDriver
)
2281 PLIST_ENTRY NextEntry
;
2282 BOOLEAN DriverFound
= FALSE
;
2283 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2284 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2285 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2288 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2289 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2292 /* Make sure there's enough system PTEs for a large page driver */
2293 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2298 /* This happens if the registry key had a "*" (wildcard) in it */
2299 if (MiLargePageAllDrivers
== 0)
2301 /* It didn't, so scan the list */
2302 NextEntry
= MiLargePageDriverList
.Flink
;
2303 while (NextEntry
!= &MiLargePageDriverList
)
2305 /* Check if the driver name matches */
2306 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2307 MI_LARGE_PAGE_DRIVER_ENTRY
,
2309 if (RtlEqualUnicodeString(BaseImageName
,
2310 &LargePageDriverEntry
->BaseName
,
2313 /* Enable large pages for this driver */
2319 NextEntry
= NextEntry
->Flink
;
2322 /* If we didn't find the driver, it doesn't need large pages */
2323 if (DriverFound
== FALSE
) return FALSE
;
2326 /* Nothing to do yet */
2327 DPRINT1("Large pages not supported!\n");
2333 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2334 IN ULONG SectionProtection
)
2336 ULONG Protection
= MM_ZERO_ACCESS
;
2338 /* Check if the caller gave anything */
2339 if (SectionProtection
)
2341 /* Always turn on execute access */
2342 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2344 /* Check if the registry setting is on or not */
2345 if (!MmEnforceWriteProtection
)
2347 /* Turn on write access too */
2348 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2352 /* Convert to internal PTE flags */
2353 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2354 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2356 /* Check for write access */
2357 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2359 /* Session space is not supported */
2362 DPRINT1("Session drivers not supported\n");
2363 ASSERT(SessionSpace
== FALSE
);
2367 /* Convert to internal PTE flag */
2368 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2372 /* If there's no access at all by now, convert to internal no access flag */
2373 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2375 /* Return the computed PTE protection */
2381 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2383 IN ULONG ProtectionMask
)
2385 /* I'm afraid to introduce regressions at the moment... */
2391 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2393 PIMAGE_NT_HEADERS NtHeaders
;
2394 PIMAGE_SECTION_HEADER Section
;
2395 PFN_NUMBER DriverPages
;
2396 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2397 ULONG Sections
, Size
;
2398 ULONG_PTR BaseAddress
, CurrentAddress
;
2399 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2400 ULONG CurrentMask
, CombinedMask
= 0;
2403 /* No need to write protect physical memory-backed drivers (large pages) */
2404 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2406 /* Get the image headers */
2407 NtHeaders
= RtlImageNtHeader(ImageBase
);
2408 if (!NtHeaders
) return;
2410 /* Check if this is a session driver or not */
2411 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2413 /* Don't touch NT4 drivers */
2414 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2415 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2420 UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n");
2423 /* These are the only protection masks we care about */
2424 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2426 /* Calculate the number of pages this driver is occupying */
2427 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2429 /* Get the number of sections and the first section header */
2430 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2431 ASSERT(Sections
!= 0);
2432 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2434 /* Loop all the sections */
2435 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2438 /* Get the section size */
2439 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2441 /* Get its virtual address */
2442 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2443 if (BaseAddress
< CurrentAddress
)
2445 /* Windows doesn't like these */
2446 DPRINT1("Badly linked image!\n");
2450 /* Remember the current address */
2451 CurrentAddress
= BaseAddress
+ Size
- 1;
2458 /* Get the number of sections and the first section header */
2459 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2460 ASSERT(Sections
!= 0);
2461 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2463 /* Set the address at the end to initialize the loop */
2464 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2465 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2467 /* Set the PTE points for the image, and loop its sections */
2468 StartPte
= MiAddressToPte(ImageBase
);
2469 LastPte
= StartPte
+ DriverPages
;
2472 /* Get the section size */
2473 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2475 /* Get its virtual address and PTE */
2476 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2477 PointerPte
= MiAddressToPte(BaseAddress
);
2479 /* Check if we were already protecting a run, and found a new run */
2480 if ((ComboPte
) && (PointerPte
> ComboPte
))
2482 /* Compute protection */
2483 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2486 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2488 /* Check for overlap */
2489 if (ComboPte
== StartPte
) StartPte
++;
2491 /* One done, reset variables */
2493 CombinedProtection
= 0;
2496 /* Break out when needed */
2497 if (PointerPte
>= LastPte
) break;
2499 /* Get the requested protection from the image header */
2500 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2501 if (SectionProtection
== CurrentProtection
)
2503 /* Same protection, so merge the request */
2504 CurrentAddress
= BaseAddress
+ Size
- 1;
2512 /* This is now a new section, so close up the old one */
2513 CurrentPte
= MiAddressToPte(CurrentAddress
);
2515 /* Check for overlap */
2516 if (CurrentPte
== PointerPte
)
2518 /* Skip the last PTE, since it overlaps with us */
2521 /* And set the PTE we will merge with */
2522 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2523 ComboPte
= PointerPte
;
2525 /* Get the most flexible protection by merging both */
2526 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2529 /* Loop any PTEs left */
2530 if (CurrentPte
>= StartPte
)
2533 ASSERT(StartPte
< LastPte
);
2535 /* Make sure we don't overflow past the last PTE in the driver */
2536 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2537 ASSERT(CurrentPte
>= StartPte
);
2539 /* Compute the protection and set it */
2540 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2541 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2545 StartPte
= PointerPte
;
2546 CurrentAddress
= BaseAddress
+ Size
- 1;
2547 CurrentProtection
= SectionProtection
;
2554 /* Is there a leftover section to merge? */
2557 /* Compute and set the protection */
2558 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2559 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2561 /* Handle overlap */
2562 if (ComboPte
== StartPte
) StartPte
++;
2565 /* Finally, handle the last section */
2566 CurrentPte
= MiAddressToPte(CurrentAddress
);
2567 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2569 /* Handle overlap */
2570 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2571 ASSERT(CurrentPte
>= StartPte
);
2573 /* Compute and set the protection */
2574 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2575 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2581 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2585 PETHREAD CurrentThread
= PsGetCurrentThread();
2586 PFN_COUNT PageCount
= 0;
2587 PFN_NUMBER PageFrameIndex
;
2591 /* The page fault handler is broken and doesn't page back in! */
2592 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
2595 /* Get the driver's base address */
2596 ImageBase
= MiPteToAddress(PointerPte
);
2597 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2599 /* If this is a large page, it's stuck in physical memory */
2600 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2602 /* Lock the working set */
2603 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2606 while (PointerPte
<= LastPte
)
2608 /* Check for valid PTE */
2609 if (PointerPte
->u
.Hard
.Valid
== 1)
2611 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2612 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2613 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2615 /* No working sets in ReactOS yet */
2619 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2623 /* Release the working set */
2624 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2626 /* Do we have any driver pages? */
2629 /* Update counters */
2630 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2636 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2638 ULONG_PTR ImageBase
;
2639 PIMAGE_NT_HEADERS NtHeaders
;
2640 ULONG Sections
, Alignment
, Size
;
2641 PIMAGE_SECTION_HEADER Section
;
2642 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2643 if (MmDisablePagingExecutive
) return;
2645 /* Get the driver base address and its NT header */
2646 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2647 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2648 if (!NtHeaders
) return;
2650 /* Get the sections and their alignment */
2651 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2652 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2654 /* Loop each section */
2655 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2658 /* Find PAGE or .edata */
2659 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2660 (*(PULONG
)Section
->Name
== 'ade.'))
2662 /* Had we already done some work? */
2665 /* Nope, setup the first PTE address */
2666 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2671 /* Compute the size */
2672 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2674 /* Find the last PTE that maps this section */
2675 LastPte
= MiAddressToPte(ImageBase
+
2676 Section
->VirtualAddress
+
2683 /* Had we found a section before? */
2686 /* Mark it as pageable */
2687 MiSetPagingOfDriver(PointerPte
, LastPte
);
2692 /* Keep searching */
2697 /* Handle the straggler */
2698 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2703 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2705 PIMAGE_NT_HEADERS NtHeader
;
2708 /* Get NT Headers */
2709 NtHeader
= RtlImageNtHeader(BaseAddress
);
2712 /* Check if this image is only safe for UP while we have 2+ CPUs */
2713 if ((KeNumberProcessors
> 1) &&
2714 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2721 /* Otherwise, it's safe */
2727 MmCheckSystemImage(IN HANDLE ImageHandle
,
2728 IN BOOLEAN PurgeSection
)
2731 HANDLE SectionHandle
;
2732 PVOID ViewBase
= NULL
;
2733 SIZE_T ViewSize
= 0;
2734 IO_STATUS_BLOCK IoStatusBlock
;
2735 FILE_STANDARD_INFORMATION FileStandardInfo
;
2736 KAPC_STATE ApcState
;
2737 PIMAGE_NT_HEADERS NtHeaders
;
2738 OBJECT_ATTRIBUTES ObjectAttributes
;
2741 /* Setup the object attributes */
2742 InitializeObjectAttributes(&ObjectAttributes
,
2744 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2748 /* Create a section for the DLL */
2749 Status
= ZwCreateSection(&SectionHandle
,
2750 SECTION_MAP_EXECUTE
,
2756 if (!NT_SUCCESS(Status
))
2758 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2762 /* Make sure we're in the system process */
2763 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2766 Status
= ZwMapViewOfSection(SectionHandle
,
2776 if (!NT_SUCCESS(Status
))
2778 /* We failed, close the handle and return */
2779 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2780 KeUnstackDetachProcess(&ApcState
);
2781 ZwClose(SectionHandle
);
2785 /* Now query image information */
2786 Status
= ZwQueryInformationFile(ImageHandle
,
2789 sizeof(FileStandardInfo
),
2790 FileStandardInformation
);
2791 if (NT_SUCCESS(Status
))
2793 /* First, verify the checksum */
2794 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2799 /* Set checksum failure */
2800 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2804 /* Make sure it's a real image */
2805 NtHeaders
= RtlImageNtHeader(ViewBase
);
2808 /* Set checksum failure */
2809 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2813 /* Make sure it's for the correct architecture */
2814 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2815 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2817 /* Set protection failure */
2818 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2822 /* Check that it's a valid SMP image if we have more then one CPU */
2823 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2825 /* Otherwise it's not the right image */
2826 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2830 /* Unmap the section, close the handle, and return status */
2832 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2833 KeUnstackDetachProcess(&ApcState
);
2834 ZwClose(SectionHandle
);
2840 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2841 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2842 IN PUNICODE_STRING LoadedName OPTIONAL
,
2844 OUT PVOID
*ModuleObject
,
2845 OUT PVOID
*ImageBaseAddress
)
2847 PVOID ModuleLoadBase
= NULL
;
2849 HANDLE FileHandle
= NULL
;
2850 OBJECT_ATTRIBUTES ObjectAttributes
;
2851 IO_STATUS_BLOCK IoStatusBlock
;
2852 PIMAGE_NT_HEADERS NtHeader
;
2853 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2854 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2855 ULONG EntrySize
, DriverSize
;
2856 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2857 PCHAR MissingApiName
, Buffer
;
2858 PWCHAR MissingDriverName
;
2859 HANDLE SectionHandle
;
2860 ACCESS_MASK DesiredAccess
;
2861 PVOID Section
= NULL
;
2862 BOOLEAN LockOwned
= FALSE
;
2863 PLIST_ENTRY NextEntry
;
2864 IMAGE_INFO ImageInfo
;
2868 /* Detect session-load */
2872 ASSERT(NamePrefix
== NULL
);
2873 ASSERT(LoadedName
== NULL
);
2875 /* Make sure the process is in session too */
2876 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2879 /* Allocate a buffer we'll use for names */
2880 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2881 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2883 /* Check for a separator */
2884 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2889 /* Loop the path until we get to the base name */
2890 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2891 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2893 /* Get the length */
2894 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2895 BaseLength
*= sizeof(WCHAR
);
2897 /* Setup the string */
2898 BaseName
.Length
= (USHORT
)BaseLength
;
2899 BaseName
.Buffer
= p
;
2903 /* Otherwise, we already have a base name */
2904 BaseName
.Length
= FileName
->Length
;
2905 BaseName
.Buffer
= FileName
->Buffer
;
2908 /* Setup the maximum length */
2909 BaseName
.MaximumLength
= BaseName
.Length
;
2911 /* Now compute the base directory */
2912 BaseDirectory
= *FileName
;
2913 BaseDirectory
.Length
-= BaseName
.Length
;
2914 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2916 /* And the prefix, which for now is just the name itself */
2917 PrefixName
= *FileName
;
2919 /* Check if we have a prefix */
2920 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2922 /* Check if we already have a name, use it instead */
2923 if (LoadedName
) BaseName
= *LoadedName
;
2925 /* Check for loader snap debugging */
2926 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2928 /* Print out standard string */
2929 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2930 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2933 /* Acquire the load lock */
2935 ASSERT(LockOwned
== FALSE
);
2937 KeEnterCriticalRegion();
2938 KeWaitForSingleObject(&MmSystemLoadLock
,
2944 /* Scan the module list */
2945 NextEntry
= PsLoadedModuleList
.Flink
;
2946 while (NextEntry
!= &PsLoadedModuleList
)
2948 /* Get the entry and compare the names */
2949 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2950 LDR_DATA_TABLE_ENTRY
,
2952 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2954 /* Found it, break out */
2959 NextEntry
= NextEntry
->Flink
;
2962 /* Check if we found the image */
2963 if (NextEntry
!= &PsLoadedModuleList
)
2965 /* Check if we had already mapped a section */
2968 /* Dereference and clear */
2969 ObDereferenceObject(Section
);
2973 /* Check if this was supposed to be a session load */
2976 /* It wasn't, so just return the data */
2977 *ModuleObject
= LdrEntry
;
2978 *ImageBaseAddress
= LdrEntry
->DllBase
;
2979 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2983 /* We don't support session loading yet */
2984 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
2985 Status
= STATUS_NOT_IMPLEMENTED
;
2993 /* It wasn't loaded, and we didn't have a previous attempt */
2994 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2995 KeLeaveCriticalRegion();
2998 /* Check if KD is enabled */
2999 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
3001 /* FIXME: Attempt to get image from KD */
3004 /* We don't have a valid entry */
3007 /* Setup image attributes */
3008 InitializeObjectAttributes(&ObjectAttributes
,
3010 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3014 /* Open the image */
3015 Status
= ZwOpenFile(&FileHandle
,
3019 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
3021 if (!NT_SUCCESS(Status
))
3023 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
3029 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
3030 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
3031 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
3032 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
3038 /* Check if this is a session-load */
3041 /* Then we only need read and execute */
3042 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
3046 /* Otherwise, we can allow write access */
3047 DesiredAccess
= SECTION_ALL_ACCESS
;
3050 /* Initialize the attributes for the section */
3051 InitializeObjectAttributes(&ObjectAttributes
,
3053 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3057 /* Create the section */
3058 Status
= ZwCreateSection(&SectionHandle
,
3065 if (!NT_SUCCESS(Status
))
3067 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3071 /* Now get the section pointer */
3072 Status
= ObReferenceObjectByHandle(SectionHandle
,
3073 SECTION_MAP_EXECUTE
,
3074 MmSectionObjectType
,
3078 ZwClose(SectionHandle
);
3079 if (!NT_SUCCESS(Status
)) goto Quickie
;
3081 /* Check if this was supposed to be a session-load */
3084 /* We don't support session loading yet */
3085 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3089 /* Check the loader list again, we should end up in the path below */
3094 /* We don't have a valid entry */
3098 /* Load the image */
3099 Status
= MiLoadImageSection(&Section
,
3104 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3106 /* Get the size of the driver */
3107 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageInformation
.ImageFileSize
;
3109 /* Make sure we're not being loaded into session space */
3112 /* Check for success */
3113 if (NT_SUCCESS(Status
))
3115 /* Support large pages for drivers */
3116 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3122 /* Dereference the section */
3123 ObDereferenceObject(Section
);
3127 /* Check for failure of the load earlier */
3128 if (!NT_SUCCESS(Status
))
3130 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3134 /* Relocate the driver */
3135 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3139 STATUS_CONFLICTING_ADDRESSES
,
3140 STATUS_INVALID_IMAGE_FORMAT
);
3141 if (!NT_SUCCESS(Status
))
3143 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3147 /* Get the NT Header */
3148 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3150 /* Calculate the size we'll need for the entry and allocate it */
3151 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3153 sizeof(UNICODE_NULL
);
3155 /* Allocate the entry */
3156 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3160 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3164 /* Setup the entry */
3165 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3166 LdrEntry
->LoadCount
= 1;
3167 LdrEntry
->LoadedImports
= LoadedImports
;
3168 LdrEntry
->PatchInformation
= NULL
;
3170 /* Check the version */
3171 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3172 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3174 /* Mark this image as a native image */
3175 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3178 /* Setup the rest of the entry */
3179 LdrEntry
->DllBase
= ModuleLoadBase
;
3180 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3181 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3182 LdrEntry
->SizeOfImage
= DriverSize
;
3183 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3184 LdrEntry
->SectionPointer
= Section
;
3186 /* Now write the DLL name */
3187 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3188 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3189 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3191 /* Copy and null-terminate it */
3192 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3195 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3197 /* Now allocate the full name */
3198 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3200 sizeof(UNICODE_NULL
),
3202 if (!LdrEntry
->FullDllName
.Buffer
)
3204 /* Don't fail, just set it to zero */
3205 LdrEntry
->FullDllName
.Length
= 0;
3206 LdrEntry
->FullDllName
.MaximumLength
= 0;
3211 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3212 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3214 /* Copy and null-terminate */
3215 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3218 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3222 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3224 /* Resolve imports */
3225 MissingApiName
= Buffer
;
3226 MissingDriverName
= NULL
;
3227 Status
= MiResolveImageReferences(ModuleLoadBase
,
3233 if (!NT_SUCCESS(Status
))
3235 BOOLEAN NeedToFreeString
= FALSE
;
3237 /* If the lowest bit is set to 1, this is a hint that we need to free */
3238 if (*(ULONG_PTR
*)&MissingDriverName
& 1)
3240 NeedToFreeString
= TRUE
;
3241 *(ULONG_PTR
*)&MissingDriverName
&= ~1;
3244 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3245 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3246 MissingDriverName
, MissingApiName
);
3248 if (NeedToFreeString
)
3250 ExFreePoolWithTag(MissingDriverName
, TAG_LDR_WSTR
);
3254 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3256 /* Check if we need to free the name */
3257 if (LdrEntry
->FullDllName
.Buffer
)
3260 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3263 /* Free the entry itself */
3264 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3269 /* Update the loader entry */
3270 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3271 LDRP_ENTRY_PROCESSED
|
3273 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3274 LdrEntry
->LoadedImports
= LoadedImports
;
3276 /* FIXME: Call driver verifier's loader function */
3278 /* Write-protect the system image */
3279 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3281 /* Check if notifications are enabled */
3282 if (PsImageNotifyEnabled
)
3284 /* Fill out the notification data */
3285 ImageInfo
.Properties
= 0;
3286 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3287 ImageInfo
.SystemModeImage
= TRUE
;
3288 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3289 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3290 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3292 /* Send the notification */
3293 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3296 #if defined(KDBG) || defined(_WINKD_)
3297 /* MiCacheImageSymbols doesn't detect rossym */
3300 /* Check if there's symbols */
3301 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3304 /* Check if the system root is present */
3305 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3306 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3308 /* Add the system root */
3309 UnicodeTemp
= PrefixName
;
3310 UnicodeTemp
.Buffer
+= 11;
3311 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3314 &SharedUserData
->NtSystemRoot
[2],
3319 /* Build the name */
3320 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3323 /* Setup the ansi string */
3324 RtlInitString(&AnsiTemp
, Buffer
);
3326 /* Notify the debugger */
3327 DbgLoadImageSymbols(&AnsiTemp
,
3329 (ULONG_PTR
)PsGetCurrentProcessId());
3330 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3333 /* Page the driver */
3334 ASSERT(Section
== NULL
);
3335 MiEnablePagingOfDriver(LdrEntry
);
3337 /* Return pointers */
3338 *ModuleObject
= LdrEntry
;
3339 *ImageBaseAddress
= LdrEntry
->DllBase
;
3342 /* Check if we have the lock acquired */
3345 /* Release the lock */
3346 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3347 KeLeaveCriticalRegion();
3351 /* If we have a file handle, close it */
3352 if (FileHandle
) ZwClose(FileHandle
);
3354 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3355 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3357 /* Free the name buffer and return status */
3358 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3362 PLDR_DATA_TABLE_ENTRY
3364 MiLookupDataTableEntry(IN PVOID Address
)
3366 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3367 PLIST_ENTRY NextEntry
;
3371 NextEntry
= PsLoadedModuleList
.Flink
;
3374 /* Get the loader entry */
3375 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3376 LDR_DATA_TABLE_ENTRY
,
3379 /* Check if the address matches */
3380 if ((Address
>= LdrEntry
->DllBase
) &&
3381 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3382 LdrEntry
->SizeOfImage
)))
3385 FoundEntry
= LdrEntry
;
3390 NextEntry
= NextEntry
->Flink
;
3391 } while(NextEntry
!= &PsLoadedModuleList
);
3393 /* Return the entry */
3397 /* PUBLIC FUNCTIONS ***********************************************************/
3404 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3406 PMMPTE StartPte
, EndPte
;
3407 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3410 /* Get the loader entry */
3411 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3412 if (!LdrEntry
) return NULL
;
3414 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3415 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3417 /* Don't do anything, just return the base address */
3418 return LdrEntry
->DllBase
;
3421 /* Wait for active DPCs to finish before we page out the driver */
3422 KeFlushQueuedDpcs();
3424 /* Get the PTE range for the whole driver image */
3425 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3426 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3428 /* Enable paging for the PTE range */
3429 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3430 MiSetPagingOfDriver(StartPte
, EndPte
);
3432 /* Return the base address */
3433 return LdrEntry
->DllBase
;
3441 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3451 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3453 PVOID ProcAddress
= NULL
;
3454 ANSI_STRING AnsiRoutineName
;
3456 PLIST_ENTRY NextEntry
;
3457 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3458 BOOLEAN Found
= FALSE
;
3459 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3460 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3463 /* Convert routine to ansi name */
3464 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3467 if (!NT_SUCCESS(Status
)) return NULL
;
3470 KeEnterCriticalRegion();
3471 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3473 /* Loop the loaded module list */
3474 NextEntry
= PsLoadedModuleList
.Flink
;
3475 while (NextEntry
!= &PsLoadedModuleList
)
3478 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3479 LDR_DATA_TABLE_ENTRY
,
3482 /* Check if it's the kernel or HAL */
3483 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3489 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3496 /* Check if we found a valid binary */
3499 /* Find the procedure name */
3500 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3503 /* Break out if we found it or if we already tried both modules */
3504 if (ProcAddress
) break;
3505 if (Modules
== 2) break;
3509 NextEntry
= NextEntry
->Flink
;
3512 /* Release the lock */
3513 ExReleaseResourceLite(&PsLoadedModuleResource
);
3514 KeLeaveCriticalRegion();
3516 /* Free the string and return */
3517 RtlFreeAnsiString(&AnsiRoutineName
);