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
+ 1);
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
;
1461 /* So we don't free our own code yet */
1462 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1464 /* Assume failure */
1467 /* Enter a critical region while we loop the list */
1468 KeEnterCriticalRegion();
1470 /* Loop all loaded modules */
1471 NextEntry
= PsLoadedModuleList
.Flink
;
1472 while (NextEntry
!= &PsLoadedModuleList
)
1474 /* Get the loader entry and its DLL base */
1475 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1476 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1478 /* Only process boot loaded images. Other drivers are processed by
1479 MmFreeDriverInitialization */
1480 if (LdrEntry
->Flags
& LDRP_MM_LOADED
)
1483 NextEntry
= NextEntry
->Flink
;
1487 /* Get the NT header */
1488 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1492 NextEntry
= NextEntry
->Flink
;
1496 /* Get the first section, the section count, and scan them all */
1497 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1498 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1500 while (SectionCount
> 0)
1502 /* Assume failure */
1505 /* Is this the INIT section or a discardable section? */
1506 if ((*(PULONG
)Section
->Name
== 'TINI') ||
1507 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1515 /* Pick the biggest size -- either raw or virtual */
1516 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1518 /* Read the section alignment */
1519 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1521 /* Align the start and end addresses appropriately */
1522 InitStart
= DllBase
+ Section
->VirtualAddress
;
1523 InitEnd
= ((Alignment
+ InitStart
+ Size
- 2) & 0xFFFFF000) - 1;
1524 InitStart
= (InitStart
+ (PAGE_SIZE
- 1)) & 0xFFFFF000;
1526 /* Have we reached the last section? */
1527 if (SectionCount
== 1)
1530 LastSection
= Section
;
1534 /* We have not, loop all the sections */
1538 /* Keep going until we find a non-discardable section range */
1541 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1543 /* Discardable, so record it, then keep going */
1544 LastSection
= Section
;
1548 /* Non-contigous discard flag, or no flag, break out */
1552 while (SectionCount
> 1);
1555 /* Have we found a discardable or init section? */
1558 /* Pick the biggest size -- either raw or virtual */
1559 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1561 /* Use this as the end of the section address */
1562 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
- 1;
1564 /* Have we reached the last section yet? */
1565 if (SectionCount
!= 1)
1567 /* Then align this accross the session boundary */
1568 InitEnd
= ((Alignment
+ InitEnd
- 1) & 0XFFFFF000) - 1;
1572 /* Make sure we don't let the init section go past the image */
1573 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1574 if (InitEnd
> ImageEnd
) InitEnd
= (ImageEnd
- 1) | (PAGE_SIZE
- 1);
1576 /* Make sure we have a valid, non-zero init section */
1577 if (InitStart
<= InitEnd
)
1579 /* Make sure we are not within this code itself */
1580 if ((InitCode
>= InitStart
) && (InitCode
<= InitEnd
))
1582 /* Return it, we can't free ourselves now */
1583 ASSERT(*StartVa
== 0);
1584 *StartVa
= (PVOID
)InitStart
;
1585 *EndVa
= (PVOID
)InitEnd
;
1589 /* This isn't us -- go ahead and free it */
1590 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1591 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1596 /* Move to the next section */
1601 /* Move to the next module */
1602 NextEntry
= NextEntry
->Flink
;
1605 /* Leave the critical region and return */
1606 KeLeaveCriticalRegion();
1610 * Note: This function assumes that all discardable sections are at the end of
1611 * the PE file. It searches backwards until it finds the non-discardable section
1615 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1617 PMMPTE StartPte
, EndPte
;
1618 PFN_NUMBER PageCount
;
1621 PIMAGE_NT_HEADERS NtHeader
;
1622 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1624 /* Get the base address and the page count */
1625 DllBase
= LdrEntry
->DllBase
;
1626 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1628 /* Get the last PTE in this image */
1629 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1631 /* Get the NT header */
1632 NtHeader
= RtlImageNtHeader(DllBase
);
1633 if (!NtHeader
) return;
1635 /* Get the last section and loop each section backwards */
1636 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1637 DiscardSection
= NULL
;
1638 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1640 /* Go back a section and check if it's discardable */
1642 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1644 /* It is, select it for freeing */
1645 DiscardSection
= Section
;
1649 /* No more discardable sections exist, bail out */
1654 /* Bail out if there's nothing to free */
1655 if (!DiscardSection
) return;
1657 /* Push the DLL base to the first disacrable section, and get its PTE */
1658 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1659 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1660 StartPte
= MiAddressToPte(DllBase
);
1662 /* Check how many pages to free total */
1663 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1664 if (!PageCount
) return;
1666 /* Delete this many PTEs */
1667 MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1673 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1675 PLIST_ENTRY NextEntry
;
1677 PIMAGE_NT_HEADERS NtHeader
;
1678 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1679 PIMAGE_FILE_HEADER FileHeader
;
1680 BOOLEAN ValidRelocs
;
1681 PIMAGE_DATA_DIRECTORY DataDirectory
;
1682 PVOID DllBase
, NewImageAddress
;
1684 PMMPTE PointerPte
, StartPte
, LastPte
;
1687 MMPTE TempPte
, OldPte
;
1689 /* Loop driver list */
1690 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1691 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1692 NextEntry
= NextEntry
->Flink
)
1694 /* Get the loader entry and NT header */
1695 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1696 LDR_DATA_TABLE_ENTRY
,
1698 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1701 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1703 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1704 &LdrEntry
->FullDllName
);
1706 /* Get the first PTE and the number of PTEs we'll need */
1707 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1708 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1709 LastPte
= StartPte
+ PteCount
;
1713 while (PointerPte
< LastPte
)
1716 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1717 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1718 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1719 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1723 /* Skip kernel and HAL */
1724 /* ROS HACK: Skip BOOTVID/KDCOM too */
1726 if (i
<= 4) continue;
1728 /* Skip non-drivers */
1729 if (!NtHeader
) continue;
1731 /* Get the file header and make sure we can relocate */
1732 FileHeader
= &NtHeader
->FileHeader
;
1733 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1734 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1735 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1737 /* Everything made sense until now, check the relocation section too */
1738 DataDirectory
= &NtHeader
->OptionalHeader
.
1739 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1740 if (!DataDirectory
->VirtualAddress
)
1742 /* We don't really have relocations */
1743 ValidRelocs
= FALSE
;
1747 /* Make sure the size is valid */
1748 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1749 LdrEntry
->SizeOfImage
)
1751 /* They're not, skip */
1755 /* We have relocations */
1759 /* Remember the original address */
1760 DllBase
= LdrEntry
->DllBase
;
1763 PointerPte
= StartPte
;
1764 while (PointerPte
< LastPte
)
1766 /* Mark the page modified in the PFN database */
1767 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1768 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1769 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1770 Pfn1
->u3
.e1
.Modified
= TRUE
;
1776 /* Now reserve system PTEs for the image */
1777 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1780 /* Shouldn't happen */
1781 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1785 /* This is the new virtual address for the module */
1786 LastPte
= PointerPte
+ PteCount
;
1787 NewImageAddress
= MiPteToAddress(PointerPte
);
1790 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1791 ASSERT(ExpInitializationPhase
== 0);
1793 /* Loop the new driver PTEs */
1794 TempPte
= ValidKernelPte
;
1795 while (PointerPte
< LastPte
)
1797 /* Copy the old data */
1799 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1801 /* Set page number from the loader's memory */
1802 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1805 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1812 /* Update position */
1813 PointerPte
-= PteCount
;
1816 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1818 /* Set the image base to the address where the loader put it */
1819 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1821 /* Check if we had relocations */
1824 /* Relocate the image */
1825 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1829 STATUS_CONFLICTING_ADDRESSES
,
1830 STATUS_INVALID_IMAGE_FORMAT
);
1831 if (!NT_SUCCESS(Status
))
1833 /* This shouldn't happen */
1834 ERROR_FATAL("Relocations failed!\n");
1839 /* Update the loader entry */
1840 LdrEntry
->DllBase
= NewImageAddress
;
1842 /* Update the thunks */
1843 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1844 MiUpdateThunks(LoaderBlock
,
1847 LdrEntry
->SizeOfImage
);
1849 /* Update the loader entry */
1850 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1851 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1852 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1853 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1855 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1862 MiBuildImportsForBootDrivers(VOID
)
1864 PLIST_ENTRY NextEntry
, NextEntry2
;
1865 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1866 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1867 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1868 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1869 PLOAD_IMPORTS LoadedImports
;
1870 ULONG LoadedImportsSize
, ImportSize
;
1871 PULONG_PTR ImageThunk
;
1872 ULONG_PTR DllBase
, DllEnd
;
1873 ULONG Modules
= 0, i
, j
= 0;
1874 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1876 /* Initialize variables */
1877 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1879 /* Loop the loaded module list... we are early enough that no lock is needed */
1880 NextEntry
= PsLoadedModuleList
.Flink
;
1881 while (NextEntry
!= &PsLoadedModuleList
)
1884 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1885 LDR_DATA_TABLE_ENTRY
,
1888 /* Check if it's the kernel or HAL */
1889 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1892 KernelEntry
= LdrEntry
;
1894 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1897 HalEntry
= LdrEntry
;
1900 /* Check if this is a driver DLL */
1901 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1903 /* Check if this is the HAL or kernel */
1904 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1906 /* Add a reference */
1907 LdrEntry
->LoadCount
= 1;
1911 /* No referencing needed */
1912 LdrEntry
->LoadCount
= 0;
1917 /* Add a reference for all other modules as well */
1918 LdrEntry
->LoadCount
= 1;
1921 /* Remember this came from the loader */
1922 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1925 NextEntry
= NextEntry
->Flink
;
1929 /* We must have at least found the kernel and HAL */
1930 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1932 /* Allocate the list */
1933 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1934 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1936 /* Loop the loaded module list again */
1937 NextEntry
= PsLoadedModuleList
.Flink
;
1938 while (NextEntry
!= &PsLoadedModuleList
)
1941 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1942 LDR_DATA_TABLE_ENTRY
,
1944 #ifdef _WORKING_LOADER_
1945 /* Get its imports */
1946 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1948 IMAGE_DIRECTORY_ENTRY_IAT
,
1952 /* Get its imports */
1953 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1955 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1957 if (!ImportDescriptor
)
1961 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1962 NextEntry
= NextEntry
->Flink
;
1966 /* Clear the list and count the number of IAT thunks */
1967 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1968 #ifdef _WORKING_LOADER_
1969 ImportSize
/= sizeof(ULONG_PTR
);
1971 /* Scan the thunks */
1972 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1974 DllBase
= DllEnd
= i
= 0;
1975 while ((ImportDescriptor
->Name
) &&
1976 (ImportDescriptor
->OriginalFirstThunk
))
1978 /* Get the image thunk */
1979 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
1980 ImportDescriptor
->FirstThunk
);
1984 /* Do we already have an address? */
1987 /* Is the thunk in the same address? */
1988 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
1990 /* Skip it, we already have a reference for it */
1991 ASSERT(EntryArray
[j
]);
1997 /* Loop the loaded module list to locate this address owner */
1999 NextEntry2
= PsLoadedModuleList
.Flink
;
2000 while (NextEntry2
!= &PsLoadedModuleList
)
2003 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
2004 LDR_DATA_TABLE_ENTRY
,
2007 /* Get the address range for this module */
2008 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
2009 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
2011 /* Check if this IAT entry matches it */
2012 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
2015 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
2016 EntryArray
[j
] = LdrEntry2
;
2020 /* Keep searching */
2021 NextEntry2
= NextEntry2
->Flink
;
2025 /* Do we have a thunk outside the range? */
2026 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
2031 /* Should not be happening */
2032 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2033 LdrEntry
, ImageThunk
, *ImageThunk
);
2036 /* Reset if we hit this */
2039 #ifndef _WORKING_LOADER_
2048 /* Now scan how many imports we really have */
2049 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
2051 /* Skip HAL and kernel */
2052 if ((EntryArray
[i
]) &&
2053 (EntryArray
[i
] != HalEntry
) &&
2054 (EntryArray
[i
] != KernelEntry
))
2056 /* A valid reference */
2057 LastEntry
= EntryArray
[i
];
2062 /* Do we have any imports after all? */
2066 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2068 else if (ImportSize
== 1)
2070 /* A single entry import */
2071 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2072 LastEntry
->LoadCount
++;
2076 /* We need an import table */
2077 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2078 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2081 ASSERT(LoadedImports
);
2083 /* Save the count */
2084 LoadedImports
->Count
= ImportSize
;
2086 /* Now copy all imports */
2087 for (i
= 0, j
= 0; i
< Modules
; i
++)
2089 /* Skip HAL and kernel */
2090 if ((EntryArray
[i
]) &&
2091 (EntryArray
[i
] != HalEntry
) &&
2092 (EntryArray
[i
] != KernelEntry
))
2094 /* A valid reference */
2095 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2096 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2097 EntryArray
[i
]->LoadCount
++;
2102 /* Should had as many entries as we expected */
2103 ASSERT(j
== ImportSize
);
2104 LdrEntry
->LoadedImports
= LoadedImports
;
2108 NextEntry
= NextEntry
->Flink
;
2111 /* Free the initial array */
2112 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2114 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2116 /* Kernel and HAL are loaded at boot */
2117 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2118 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2120 /* All worked well */
2121 return STATUS_SUCCESS
;
2127 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2130 PIMAGE_NT_HEADERS NtHeaders
;
2131 PIMAGE_SECTION_HEADER SectionHeader
;
2132 ULONG Sections
, Size
;
2134 /* Get the kernel section header */
2135 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2136 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2137 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2139 /* Loop all the sections */
2140 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2143 /* Grab the size of the section */
2144 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2146 /* Check for .RSRC section */
2147 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2149 /* Remember the PTEs so we can modify them later */
2150 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2151 SectionHeader
->VirtualAddress
);
2152 MiKernelResourceEndPte
= MiKernelResourceStartPte
+
2153 BYTES_TO_PAGES(SectionHeader
->VirtualAddress
+ Size
);
2155 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2157 /* POOLCODE vs. POOLMI */
2158 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2160 /* Found Ex* Pool code */
2161 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2162 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2164 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2166 /* Found Mm* Pool code */
2167 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2168 MmPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2171 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2172 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2174 /* Found MISYSPTE (Mm System PTE code)*/
2175 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2176 MmPteCodeEnd
= ExPoolCodeStart
+ Size
;
2188 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2190 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2191 PLIST_ENTRY ListHead
, NextEntry
;
2194 /* Setup the loaded module list and locks */
2195 ExInitializeResourceLite(&PsLoadedModuleResource
);
2196 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2197 InitializeListHead(&PsLoadedModuleList
);
2199 /* Get loop variables and the kernel entry */
2200 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2201 NextEntry
= ListHead
->Flink
;
2202 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2203 LDR_DATA_TABLE_ENTRY
,
2205 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2207 /* Locate resource section, pool code, and system pte code */
2208 MiLocateKernelSections(LdrEntry
);
2210 /* Loop the loader block */
2211 while (NextEntry
!= ListHead
)
2213 /* Get the loader entry */
2214 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2215 LDR_DATA_TABLE_ENTRY
,
2218 /* FIXME: ROS HACK. Make sure this is a driver */
2219 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2221 /* Skip this entry */
2222 NextEntry
= NextEntry
->Flink
;
2226 /* Calculate the size we'll need and allocate a copy */
2227 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2228 LdrEntry
->BaseDllName
.MaximumLength
+
2229 sizeof(UNICODE_NULL
);
2230 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2231 if (!NewEntry
) return FALSE
;
2233 /* Copy the entry over */
2234 *NewEntry
= *LdrEntry
;
2236 /* Allocate the name */
2237 NewEntry
->FullDllName
.Buffer
=
2238 ExAllocatePoolWithTag(PagedPool
,
2239 LdrEntry
->FullDllName
.MaximumLength
+
2240 sizeof(UNICODE_NULL
),
2242 if (!NewEntry
->FullDllName
.Buffer
)
2244 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2248 /* Set the base name */
2249 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2251 /* Copy the full and base name */
2252 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2253 LdrEntry
->FullDllName
.Buffer
,
2254 LdrEntry
->FullDllName
.MaximumLength
);
2255 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2256 LdrEntry
->BaseDllName
.Buffer
,
2257 LdrEntry
->BaseDllName
.MaximumLength
);
2259 /* Null-terminate the base name */
2260 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2261 sizeof(WCHAR
)] = UNICODE_NULL
;
2263 /* Insert the entry into the list */
2264 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2265 NextEntry
= NextEntry
->Flink
;
2268 /* Build the import lists for the boot drivers */
2269 MiBuildImportsForBootDrivers();
2277 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2278 IN OUT PVOID
*ImageBaseAddress
,
2279 IN PUNICODE_STRING BaseImageName
,
2280 IN BOOLEAN BootDriver
)
2282 PLIST_ENTRY NextEntry
;
2283 BOOLEAN DriverFound
= FALSE
;
2284 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2285 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2286 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2289 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2290 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2293 /* Make sure there's enough system PTEs for a large page driver */
2294 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2299 /* This happens if the registry key had a "*" (wildcard) in it */
2300 if (MiLargePageAllDrivers
== 0)
2302 /* It didn't, so scan the list */
2303 NextEntry
= MiLargePageDriverList
.Flink
;
2304 while (NextEntry
!= &MiLargePageDriverList
)
2306 /* Check if the driver name matches */
2307 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2308 MI_LARGE_PAGE_DRIVER_ENTRY
,
2310 if (RtlEqualUnicodeString(BaseImageName
,
2311 &LargePageDriverEntry
->BaseName
,
2314 /* Enable large pages for this driver */
2320 NextEntry
= NextEntry
->Flink
;
2323 /* If we didn't find the driver, it doesn't need large pages */
2324 if (DriverFound
== FALSE
) return FALSE
;
2327 /* Nothing to do yet */
2328 DPRINT1("Large pages not supported!\n");
2334 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
2335 IN ULONG SectionProtection
)
2337 ULONG Protection
= MM_ZERO_ACCESS
;
2339 /* Check if the caller gave anything */
2340 if (SectionProtection
)
2342 /* Always turn on execute access */
2343 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
2345 /* Check if the registry setting is on or not */
2346 if (!MmEnforceWriteProtection
)
2348 /* Turn on write access too */
2349 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
2353 /* Convert to internal PTE flags */
2354 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
2355 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
2357 /* Check for write access */
2358 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
2360 /* Session space is not supported */
2363 DPRINT1("Session drivers not supported\n");
2364 ASSERT(SessionSpace
== FALSE
);
2368 /* Convert to internal PTE flag */
2369 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
2373 /* If there's no access at all by now, convert to internal no access flag */
2374 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
2376 /* Return the computed PTE protection */
2382 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
2384 IN ULONG ProtectionMask
)
2386 /* I'm afraid to introduce regressions at the moment... */
2392 MiWriteProtectSystemImage(IN PVOID ImageBase
)
2394 PIMAGE_NT_HEADERS NtHeaders
;
2395 PIMAGE_SECTION_HEADER Section
;
2396 PFN_NUMBER DriverPages
;
2397 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
= 0, ProtectionMask
;
2398 ULONG Sections
, Size
;
2399 ULONG_PTR BaseAddress
, CurrentAddress
;
2400 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
2401 ULONG CurrentMask
, CombinedMask
= 0;
2404 /* No need to write protect physical memory-backed drivers (large pages) */
2405 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2407 /* Get the image headers */
2408 NtHeaders
= RtlImageNtHeader(ImageBase
);
2409 if (!NtHeaders
) return;
2411 /* Check if this is a session driver or not */
2412 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
2414 /* Don't touch NT4 drivers */
2415 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
2416 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
2421 UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n");
2424 /* These are the only protection masks we care about */
2425 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
2427 /* Calculate the number of pages this driver is occupying */
2428 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
2430 /* Get the number of sections and the first section header */
2431 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2432 ASSERT(Sections
!= 0);
2433 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2435 /* Loop all the sections */
2436 CurrentAddress
= (ULONG_PTR
)ImageBase
;
2439 /* Get the section size */
2440 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2442 /* Get its virtual address */
2443 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2444 if (BaseAddress
< CurrentAddress
)
2446 /* Windows doesn't like these */
2447 DPRINT1("Badly linked image!\n");
2451 /* Remember the current address */
2452 CurrentAddress
= BaseAddress
+ Size
- 1;
2459 /* Get the number of sections and the first section header */
2460 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2461 ASSERT(Sections
!= 0);
2462 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2464 /* Set the address at the end to initialize the loop */
2465 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
2466 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
2468 /* Set the PTE points for the image, and loop its sections */
2469 StartPte
= MiAddressToPte(ImageBase
);
2470 LastPte
= StartPte
+ DriverPages
;
2473 /* Get the section size */
2474 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2476 /* Get its virtual address and PTE */
2477 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
2478 PointerPte
= MiAddressToPte(BaseAddress
);
2480 /* Check if we were already protecting a run, and found a new run */
2481 if ((ComboPte
) && (PointerPte
> ComboPte
))
2483 /* Compute protection */
2484 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2487 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2489 /* Check for overlap */
2490 if (ComboPte
== StartPte
) StartPte
++;
2492 /* One done, reset variables */
2494 CombinedProtection
= 0;
2497 /* Break out when needed */
2498 if (PointerPte
>= LastPte
) break;
2500 /* Get the requested protection from the image header */
2501 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
2502 if (SectionProtection
== CurrentProtection
)
2504 /* Same protection, so merge the request */
2505 CurrentAddress
= BaseAddress
+ Size
- 1;
2513 /* This is now a new section, so close up the old one */
2514 CurrentPte
= MiAddressToPte(CurrentAddress
);
2516 /* Check for overlap */
2517 if (CurrentPte
== PointerPte
)
2519 /* Skip the last PTE, since it overlaps with us */
2522 /* And set the PTE we will merge with */
2523 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
2524 ComboPte
= PointerPte
;
2526 /* Get the most flexible protection by merging both */
2527 CombinedMask
|= (SectionProtection
| CurrentProtection
);
2530 /* Loop any PTEs left */
2531 if (CurrentPte
>= StartPte
)
2534 ASSERT(StartPte
< LastPte
);
2536 /* Make sure we don't overflow past the last PTE in the driver */
2537 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2538 ASSERT(CurrentPte
>= StartPte
);
2540 /* Compute the protection and set it */
2541 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2542 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2546 StartPte
= PointerPte
;
2547 CurrentAddress
= BaseAddress
+ Size
- 1;
2548 CurrentProtection
= SectionProtection
;
2555 /* Is there a leftover section to merge? */
2558 /* Compute and set the protection */
2559 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
2560 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
2562 /* Handle overlap */
2563 if (ComboPte
== StartPte
) StartPte
++;
2566 /* Finally, handle the last section */
2567 CurrentPte
= MiAddressToPte(CurrentAddress
);
2568 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
2570 /* Handle overlap */
2571 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
2572 ASSERT(CurrentPte
>= StartPte
);
2574 /* Compute and set the protection */
2575 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
2576 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
2582 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2586 PETHREAD CurrentThread
= PsGetCurrentThread();
2587 PFN_COUNT PageCount
= 0;
2588 PFN_NUMBER PageFrameIndex
;
2592 /* The page fault handler is broken and doesn't page back in! */
2593 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
2596 /* Get the driver's base address */
2597 ImageBase
= MiPteToAddress(PointerPte
);
2598 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2600 /* If this is a large page, it's stuck in physical memory */
2601 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2603 /* Lock the working set */
2604 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2607 while (PointerPte
<= LastPte
)
2609 /* Check for valid PTE */
2610 if (PointerPte
->u
.Hard
.Valid
== 1)
2612 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2613 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2614 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2616 /* No working sets in ReactOS yet */
2620 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2624 /* Release the working set */
2625 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2627 /* Do we have any driver pages? */
2630 /* Update counters */
2631 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2637 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2639 ULONG_PTR ImageBase
;
2640 PIMAGE_NT_HEADERS NtHeaders
;
2641 ULONG Sections
, Alignment
, Size
;
2642 PIMAGE_SECTION_HEADER Section
;
2643 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2644 if (MmDisablePagingExecutive
) return;
2646 /* Get the driver base address and its NT header */
2647 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2648 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2649 if (!NtHeaders
) return;
2651 /* Get the sections and their alignment */
2652 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2653 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2655 /* Loop each section */
2656 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2659 /* Find PAGE or .edata */
2660 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2661 (*(PULONG
)Section
->Name
== 'ade.'))
2663 /* Had we already done some work? */
2666 /* Nope, setup the first PTE address */
2667 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2672 /* Compute the size */
2673 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2675 /* Find the last PTE that maps this section */
2676 LastPte
= MiAddressToPte(ImageBase
+
2677 Section
->VirtualAddress
+
2684 /* Had we found a section before? */
2687 /* Mark it as pageable */
2688 MiSetPagingOfDriver(PointerPte
, LastPte
);
2693 /* Keep searching */
2698 /* Handle the straggler */
2699 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2704 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2706 PIMAGE_NT_HEADERS NtHeader
;
2709 /* Get NT Headers */
2710 NtHeader
= RtlImageNtHeader(BaseAddress
);
2713 /* Check if this image is only safe for UP while we have 2+ CPUs */
2714 if ((KeNumberProcessors
> 1) &&
2715 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2722 /* Otherwise, it's safe */
2728 MmCheckSystemImage(IN HANDLE ImageHandle
,
2729 IN BOOLEAN PurgeSection
)
2732 HANDLE SectionHandle
;
2733 PVOID ViewBase
= NULL
;
2734 SIZE_T ViewSize
= 0;
2735 IO_STATUS_BLOCK IoStatusBlock
;
2736 FILE_STANDARD_INFORMATION FileStandardInfo
;
2737 KAPC_STATE ApcState
;
2738 PIMAGE_NT_HEADERS NtHeaders
;
2739 OBJECT_ATTRIBUTES ObjectAttributes
;
2742 /* Setup the object attributes */
2743 InitializeObjectAttributes(&ObjectAttributes
,
2745 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2749 /* Create a section for the DLL */
2750 Status
= ZwCreateSection(&SectionHandle
,
2751 SECTION_MAP_EXECUTE
,
2757 if (!NT_SUCCESS(Status
))
2759 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2763 /* Make sure we're in the system process */
2764 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2767 Status
= ZwMapViewOfSection(SectionHandle
,
2777 if (!NT_SUCCESS(Status
))
2779 /* We failed, close the handle and return */
2780 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2781 KeUnstackDetachProcess(&ApcState
);
2782 ZwClose(SectionHandle
);
2786 /* Now query image information */
2787 Status
= ZwQueryInformationFile(ImageHandle
,
2790 sizeof(FileStandardInfo
),
2791 FileStandardInformation
);
2792 if (NT_SUCCESS(Status
))
2794 /* First, verify the checksum */
2795 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2800 /* Set checksum failure */
2801 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2805 /* Make sure it's a real image */
2806 NtHeaders
= RtlImageNtHeader(ViewBase
);
2809 /* Set checksum failure */
2810 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2814 /* Make sure it's for the correct architecture */
2815 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2816 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2818 /* Set protection failure */
2819 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2823 /* Check that it's a valid SMP image if we have more then one CPU */
2824 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2826 /* Otherwise it's not the right image */
2827 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2831 /* Unmap the section, close the handle, and return status */
2833 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2834 KeUnstackDetachProcess(&ApcState
);
2835 ZwClose(SectionHandle
);
2841 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2842 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2843 IN PUNICODE_STRING LoadedName OPTIONAL
,
2845 OUT PVOID
*ModuleObject
,
2846 OUT PVOID
*ImageBaseAddress
)
2848 PVOID ModuleLoadBase
= NULL
;
2850 HANDLE FileHandle
= NULL
;
2851 OBJECT_ATTRIBUTES ObjectAttributes
;
2852 IO_STATUS_BLOCK IoStatusBlock
;
2853 PIMAGE_NT_HEADERS NtHeader
;
2854 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2855 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2856 ULONG EntrySize
, DriverSize
;
2857 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2858 PCHAR MissingApiName
, Buffer
;
2859 PWCHAR MissingDriverName
;
2860 HANDLE SectionHandle
;
2861 ACCESS_MASK DesiredAccess
;
2862 PVOID Section
= NULL
;
2863 BOOLEAN LockOwned
= FALSE
;
2864 PLIST_ENTRY NextEntry
;
2865 IMAGE_INFO ImageInfo
;
2869 /* Detect session-load */
2873 ASSERT(NamePrefix
== NULL
);
2874 ASSERT(LoadedName
== NULL
);
2876 /* Make sure the process is in session too */
2877 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2880 /* Allocate a buffer we'll use for names */
2881 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
2882 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2884 /* Check for a separator */
2885 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2890 /* Loop the path until we get to the base name */
2891 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2892 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2894 /* Get the length */
2895 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2896 BaseLength
*= sizeof(WCHAR
);
2898 /* Setup the string */
2899 BaseName
.Length
= (USHORT
)BaseLength
;
2900 BaseName
.Buffer
= p
;
2904 /* Otherwise, we already have a base name */
2905 BaseName
.Length
= FileName
->Length
;
2906 BaseName
.Buffer
= FileName
->Buffer
;
2909 /* Setup the maximum length */
2910 BaseName
.MaximumLength
= BaseName
.Length
;
2912 /* Now compute the base directory */
2913 BaseDirectory
= *FileName
;
2914 BaseDirectory
.Length
-= BaseName
.Length
;
2915 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2917 /* And the prefix, which for now is just the name itself */
2918 PrefixName
= *FileName
;
2920 /* Check if we have a prefix */
2921 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2923 /* Check if we already have a name, use it instead */
2924 if (LoadedName
) BaseName
= *LoadedName
;
2926 /* Check for loader snap debugging */
2927 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2929 /* Print out standard string */
2930 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2931 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2934 /* Acquire the load lock */
2936 ASSERT(LockOwned
== FALSE
);
2938 KeEnterCriticalRegion();
2939 KeWaitForSingleObject(&MmSystemLoadLock
,
2945 /* Scan the module list */
2946 NextEntry
= PsLoadedModuleList
.Flink
;
2947 while (NextEntry
!= &PsLoadedModuleList
)
2949 /* Get the entry and compare the names */
2950 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2951 LDR_DATA_TABLE_ENTRY
,
2953 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2955 /* Found it, break out */
2960 NextEntry
= NextEntry
->Flink
;
2963 /* Check if we found the image */
2964 if (NextEntry
!= &PsLoadedModuleList
)
2966 /* Check if we had already mapped a section */
2969 /* Dereference and clear */
2970 ObDereferenceObject(Section
);
2974 /* Check if this was supposed to be a session load */
2977 /* It wasn't, so just return the data */
2978 *ModuleObject
= LdrEntry
;
2979 *ImageBaseAddress
= LdrEntry
->DllBase
;
2980 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2984 /* We don't support session loading yet */
2985 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
2986 Status
= STATUS_NOT_IMPLEMENTED
;
2994 /* It wasn't loaded, and we didn't have a previous attempt */
2995 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2996 KeLeaveCriticalRegion();
2999 /* Check if KD is enabled */
3000 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
3002 /* FIXME: Attempt to get image from KD */
3005 /* We don't have a valid entry */
3008 /* Setup image attributes */
3009 InitializeObjectAttributes(&ObjectAttributes
,
3011 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3015 /* Open the image */
3016 Status
= ZwOpenFile(&FileHandle
,
3020 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
3022 if (!NT_SUCCESS(Status
))
3024 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
3030 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
3031 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
3032 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
3033 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
3039 /* Check if this is a session-load */
3042 /* Then we only need read and execute */
3043 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
3047 /* Otherwise, we can allow write access */
3048 DesiredAccess
= SECTION_ALL_ACCESS
;
3051 /* Initialize the attributes for the section */
3052 InitializeObjectAttributes(&ObjectAttributes
,
3054 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3058 /* Create the section */
3059 Status
= ZwCreateSection(&SectionHandle
,
3066 if (!NT_SUCCESS(Status
))
3068 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3072 /* Now get the section pointer */
3073 Status
= ObReferenceObjectByHandle(SectionHandle
,
3074 SECTION_MAP_EXECUTE
,
3075 MmSectionObjectType
,
3079 ZwClose(SectionHandle
);
3080 if (!NT_SUCCESS(Status
)) goto Quickie
;
3082 /* Check if this was supposed to be a session-load */
3085 /* We don't support session loading yet */
3086 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3090 /* Check the loader list again, we should end up in the path below */
3095 /* We don't have a valid entry */
3099 /* Load the image */
3100 Status
= MiLoadImageSection(&Section
,
3105 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3107 /* Get the size of the driver */
3108 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageInformation
.ImageFileSize
;
3110 /* Make sure we're not being loaded into session space */
3113 /* Check for success */
3114 if (NT_SUCCESS(Status
))
3116 /* Support large pages for drivers */
3117 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3123 /* Dereference the section */
3124 ObDereferenceObject(Section
);
3128 /* Check for failure of the load earlier */
3129 if (!NT_SUCCESS(Status
))
3131 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3135 /* Relocate the driver */
3136 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3140 STATUS_CONFLICTING_ADDRESSES
,
3141 STATUS_INVALID_IMAGE_FORMAT
);
3142 if (!NT_SUCCESS(Status
))
3144 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3148 /* Get the NT Header */
3149 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3151 /* Calculate the size we'll need for the entry and allocate it */
3152 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3154 sizeof(UNICODE_NULL
);
3156 /* Allocate the entry */
3157 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3161 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3165 /* Setup the entry */
3166 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3167 LdrEntry
->LoadCount
= 1;
3168 LdrEntry
->LoadedImports
= LoadedImports
;
3169 LdrEntry
->PatchInformation
= NULL
;
3171 /* Check the version */
3172 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3173 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3175 /* Mark this image as a native image */
3176 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3179 /* Setup the rest of the entry */
3180 LdrEntry
->DllBase
= ModuleLoadBase
;
3181 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3182 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3183 LdrEntry
->SizeOfImage
= DriverSize
;
3184 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3185 LdrEntry
->SectionPointer
= Section
;
3187 /* Now write the DLL name */
3188 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3189 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3190 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3192 /* Copy and null-terminate it */
3193 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3196 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3198 /* Now allocate the full name */
3199 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3201 sizeof(UNICODE_NULL
),
3203 if (!LdrEntry
->FullDllName
.Buffer
)
3205 /* Don't fail, just set it to zero */
3206 LdrEntry
->FullDllName
.Length
= 0;
3207 LdrEntry
->FullDllName
.MaximumLength
= 0;
3212 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3213 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3215 /* Copy and null-terminate */
3216 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3219 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3223 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3225 /* Resolve imports */
3226 MissingApiName
= Buffer
;
3227 MissingDriverName
= NULL
;
3228 Status
= MiResolveImageReferences(ModuleLoadBase
,
3234 if (!NT_SUCCESS(Status
))
3236 BOOLEAN NeedToFreeString
= FALSE
;
3238 /* If the lowest bit is set to 1, this is a hint that we need to free */
3239 if (*(ULONG_PTR
*)&MissingDriverName
& 1)
3241 NeedToFreeString
= TRUE
;
3242 *(ULONG_PTR
*)&MissingDriverName
&= ~1;
3245 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3246 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3247 MissingDriverName
, MissingApiName
);
3249 if (NeedToFreeString
)
3251 ExFreePoolWithTag(MissingDriverName
, TAG_LDR_WSTR
);
3255 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3257 /* Check if we need to free the name */
3258 if (LdrEntry
->FullDllName
.Buffer
)
3261 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3264 /* Free the entry itself */
3265 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3270 /* Update the loader entry */
3271 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3272 LDRP_ENTRY_PROCESSED
|
3274 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3275 LdrEntry
->LoadedImports
= LoadedImports
;
3277 /* FIXME: Call driver verifier's loader function */
3279 /* Write-protect the system image */
3280 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3282 /* Check if notifications are enabled */
3283 if (PsImageNotifyEnabled
)
3285 /* Fill out the notification data */
3286 ImageInfo
.Properties
= 0;
3287 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3288 ImageInfo
.SystemModeImage
= TRUE
;
3289 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3290 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3291 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3293 /* Send the notification */
3294 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3297 #if defined(KDBG) || defined(_WINKD_)
3298 /* MiCacheImageSymbols doesn't detect rossym */
3301 /* Check if there's symbols */
3302 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3305 /* Check if the system root is present */
3306 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3307 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3309 /* Add the system root */
3310 UnicodeTemp
= PrefixName
;
3311 UnicodeTemp
.Buffer
+= 11;
3312 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3315 &SharedUserData
->NtSystemRoot
[2],
3320 /* Build the name */
3321 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3324 /* Setup the ansi string */
3325 RtlInitString(&AnsiTemp
, Buffer
);
3327 /* Notify the debugger */
3328 DbgLoadImageSymbols(&AnsiTemp
,
3330 (ULONG_PTR
)PsGetCurrentProcessId());
3331 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3334 /* Page the driver */
3335 ASSERT(Section
== NULL
);
3336 MiEnablePagingOfDriver(LdrEntry
);
3338 /* Return pointers */
3339 *ModuleObject
= LdrEntry
;
3340 *ImageBaseAddress
= LdrEntry
->DllBase
;
3343 /* Check if we have the lock acquired */
3346 /* Release the lock */
3347 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3348 KeLeaveCriticalRegion();
3352 /* If we have a file handle, close it */
3353 if (FileHandle
) ZwClose(FileHandle
);
3355 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3356 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3358 /* Free the name buffer and return status */
3359 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3363 PLDR_DATA_TABLE_ENTRY
3365 MiLookupDataTableEntry(IN PVOID Address
)
3367 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3368 PLIST_ENTRY NextEntry
;
3372 NextEntry
= PsLoadedModuleList
.Flink
;
3375 /* Get the loader entry */
3376 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3377 LDR_DATA_TABLE_ENTRY
,
3380 /* Check if the address matches */
3381 if ((Address
>= LdrEntry
->DllBase
) &&
3382 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3383 LdrEntry
->SizeOfImage
)))
3386 FoundEntry
= LdrEntry
;
3391 NextEntry
= NextEntry
->Flink
;
3392 } while(NextEntry
!= &PsLoadedModuleList
);
3394 /* Return the entry */
3398 /* PUBLIC FUNCTIONS ***********************************************************/
3405 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3407 PMMPTE StartPte
, EndPte
;
3408 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3411 /* Get the loader entry */
3412 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3413 if (!LdrEntry
) return NULL
;
3415 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3416 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3418 /* Don't do anything, just return the base address */
3419 return LdrEntry
->DllBase
;
3422 /* Wait for active DPCs to finish before we page out the driver */
3423 KeFlushQueuedDpcs();
3425 /* Get the PTE range for the whole driver image */
3426 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3427 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3429 /* Enable paging for the PTE range */
3430 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3431 MiSetPagingOfDriver(StartPte
, EndPte
);
3433 /* Return the base address */
3434 return LdrEntry
->DllBase
;
3442 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3452 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3454 PVOID ProcAddress
= NULL
;
3455 ANSI_STRING AnsiRoutineName
;
3457 PLIST_ENTRY NextEntry
;
3458 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3459 BOOLEAN Found
= FALSE
;
3460 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3461 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3464 /* Convert routine to ansi name */
3465 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3468 if (!NT_SUCCESS(Status
)) return NULL
;
3471 KeEnterCriticalRegion();
3472 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3474 /* Loop the loaded module list */
3475 NextEntry
= PsLoadedModuleList
.Flink
;
3476 while (NextEntry
!= &PsLoadedModuleList
)
3479 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3480 LDR_DATA_TABLE_ENTRY
,
3483 /* Check if it's the kernel or HAL */
3484 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3490 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3497 /* Check if we found a valid binary */
3500 /* Find the procedure name */
3501 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3504 /* Break out if we found it or if we already tried both modules */
3505 if (ProcAddress
) break;
3506 if (Modules
== 2) break;
3510 NextEntry
= NextEntry
->Flink
;
3513 /* Release the lock */
3514 ExReleaseResourceLite(&PsLoadedModuleResource
);
3515 KeLeaveCriticalRegion();
3517 /* Free the string and return */
3518 RtlFreeAnsiString(&AnsiRoutineName
);