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
;
324 * Do a temporary copy of BaseDllName called ImportName
325 * because we'll alter the length of the string.
327 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
328 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
329 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
331 /* Obtain the path to this dll's service in the registry */
332 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
333 ImportName
.Length
+ sizeof(UNICODE_NULL
);
334 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
335 RegPath
.MaximumLength
,
338 /* Check if this allocation was unsuccessful */
339 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
341 /* Build and append the service name itself */
342 RegPath
.Length
= ServicesKeyName
.Length
;
343 RtlCopyMemory(RegPath
.Buffer
,
344 ServicesKeyName
.Buffer
,
345 ServicesKeyName
.Length
);
347 /* Check if there is a dot in the filename */
348 if (wcschr(ImportName
.Buffer
, L
'.'))
350 /* Remove the extension */
351 ImportName
.Length
= (USHORT
)(wcschr(ImportName
.Buffer
, L
'.') -
352 ImportName
.Buffer
) * sizeof(WCHAR
);
355 /* Append service name (the basename without extension) */
356 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
358 /* Now call the DllInit func */
359 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
360 Status
= DllInit(&RegPath
);
363 ExFreePoolWithTag(RegPath
.Buffer
, TAG_LDR_WSTR
);
365 /* Return status value which DllInitialize returned */
371 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
377 /* Get the unload routine */
378 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
379 if (!Func
) return FALSE
;
381 /* Call it and check for success */
383 if (!NT_SUCCESS(Status
)) return FALSE
;
385 /* Lie about the load count so we can unload the image */
386 ASSERT(LdrEntry
->LoadCount
== 0);
387 LdrEntry
->LoadCount
= 1;
389 /* Unload it and return true */
390 MmUnloadSystemImage(LdrEntry
);
396 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
399 LOAD_IMPORTS SingleEntry
;
400 PLDR_DATA_TABLE_ENTRY LdrEntry
;
401 PVOID CurrentImports
;
404 /* Check if there's no imports or if we're a boot driver */
405 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
406 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
407 (ImportList
->Count
== 0))
409 /* Then there's nothing to do */
410 return STATUS_SUCCESS
;
413 /* Check for single-entry */
414 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
417 SingleEntry
.Count
= 1;
418 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
420 /* Use this as the import list */
421 ImportList
= &SingleEntry
;
424 /* Loop the import list */
425 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
428 LdrEntry
= ImportList
->Entry
[i
];
429 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
431 /* Skip boot loaded images */
432 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
434 /* Dereference the entry */
435 ASSERT(LdrEntry
->LoadCount
>= 1);
436 if (!--LdrEntry
->LoadCount
)
438 /* Save the import data in case unload fails */
439 CurrentImports
= LdrEntry
->LoadedImports
;
441 /* This is the last entry */
442 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
443 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
445 /* Unloading worked, parse this DLL's imports too */
446 MiDereferenceImports(CurrentImports
);
448 /* Check if we had valid imports */
449 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) &&
450 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) &&
451 !((ULONG_PTR
)CurrentImports
& MM_SYSLDR_SINGLE_ENTRY
))
454 ExFreePoolWithTag(CurrentImports
, TAG_LDR_IMPORTS
);
459 /* Unload failed, restore imports */
460 LdrEntry
->LoadedImports
= CurrentImports
;
466 return STATUS_SUCCESS
;
471 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
475 /* Check if there's no imports or we're a boot driver or only one entry */
476 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
477 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
478 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
484 /* Otherwise, free the import list */
485 ExFreePoolWithTag(LdrEntry
->LoadedImports
, TAG_LDR_IMPORTS
);
486 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
491 MiFindExportedRoutineByName(IN PVOID DllBase
,
492 IN PANSI_STRING ExportName
)
495 PUSHORT OrdinalTable
;
496 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
497 LONG Low
= 0, Mid
= 0, High
, Ret
;
504 /* Get the export directory */
505 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
507 IMAGE_DIRECTORY_ENTRY_EXPORT
,
509 if (!ExportDirectory
) return NULL
;
511 /* Setup name tables */
512 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
513 ExportDirectory
->AddressOfNames
);
514 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
515 ExportDirectory
->AddressOfNameOrdinals
);
517 /* Do a binary search */
518 High
= ExportDirectory
->NumberOfNames
- 1;
521 /* Get new middle value */
522 Mid
= (Low
+ High
) >> 1;
525 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
543 /* Check if we couldn't find it */
544 if (High
< Low
) return NULL
;
546 /* Otherwise, this is the ordinal */
547 Ordinal
= OrdinalTable
[Mid
];
549 /* Validate the ordinal */
550 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
) return NULL
;
552 /* Resolve the address and write it */
553 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
554 ExportDirectory
->AddressOfFunctions
);
555 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
558 ASSERT((Function
< (PVOID
)ExportDirectory
) ||
559 (Function
> (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
566 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
571 /* Acquire module list lock */
572 KeEnterCriticalRegion();
573 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
575 /* Acquire the spinlock too as we will insert or remove the entry */
576 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
578 /* Insert or remove from the list */
580 InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
);
582 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
585 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
586 ExReleaseResourceLite(&PsLoadedModuleResource
);
587 KeLeaveCriticalRegion();
593 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
598 ULONG_PTR OldBaseTop
, Delta
;
599 PLDR_DATA_TABLE_ENTRY LdrEntry
;
600 PLIST_ENTRY NextEntry
;
603 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
604 // since a real version of Windows would fail at this point, but they seem
605 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
606 // a feature which isn't even used by Windows. Priorities, priorities...
607 // Please note that Microsoft WDK EULA and license prohibits using
608 // the information contained within it for the generation of "non-Windows"
609 // drivers, which is precisely what LD will generate, since an LD driver
610 // will not load on Windows.
612 #ifdef _WORKING_LINKER_
615 PULONG_PTR ImageThunk
;
616 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
618 /* Calculate the top and delta */
619 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
620 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
622 /* Loop the loader block */
623 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
624 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
625 NextEntry
= NextEntry
->Flink
)
627 /* Get the loader entry */
628 LdrEntry
= CONTAINING_RECORD(NextEntry
,
629 LDR_DATA_TABLE_ENTRY
,
631 #ifdef _WORKING_LINKER_
633 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
635 IMAGE_DIRECTORY_ENTRY_IAT
,
637 if (!ImageThunk
) continue;
639 /* Make sure we have an IAT */
640 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
641 for (i
= 0; i
< ImportSize
; i
++, ImageThunk
++)
643 /* Check if it's within this module */
644 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
647 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
648 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
649 *ImageThunk
+= Delta
;
653 /* Get the import table */
654 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
656 IMAGE_DIRECTORY_ENTRY_IMPORT
,
658 if (!ImportDescriptor
) continue;
660 /* Make sure we have an IAT */
661 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
662 while ((ImportDescriptor
->Name
) &&
663 (ImportDescriptor
->OriginalFirstThunk
))
665 /* Get the image thunk */
666 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
667 ImportDescriptor
->FirstThunk
);
670 /* Check if it's within this module */
671 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
674 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
675 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
676 *ImageThunk
+= Delta
;
679 /* Go to the next thunk */
683 /* Go to the next import */
692 MiSnapThunk(IN PVOID DllBase
,
694 IN PIMAGE_THUNK_DATA Name
,
695 IN PIMAGE_THUNK_DATA Address
,
696 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
698 IN BOOLEAN SnapForwarder
,
699 OUT PCHAR
*MissingApi
)
704 PUSHORT OrdinalTable
;
705 PIMAGE_IMPORT_BY_NAME NameImport
;
707 ULONG Low
= 0, Mid
= 0, High
;
710 PCHAR MissingForwarder
;
711 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
714 UNICODE_STRING ForwarderName
;
715 PLIST_ENTRY NextEntry
;
716 PLDR_DATA_TABLE_ENTRY LdrEntry
;
717 ULONG ForwardExportSize
;
718 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
719 PIMAGE_IMPORT_BY_NAME ForwardName
;
720 SIZE_T ForwardLength
;
721 IMAGE_THUNK_DATA ForwardThunk
;
724 /* Check if this is an ordinal */
725 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
726 if ((IsOrdinal
) && !(SnapForwarder
))
728 /* Get the ordinal number and set it as missing */
729 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
730 ExportDirectory
->Base
);
731 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
735 /* Get the VA if we don't have to snap */
736 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
737 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
739 /* Copy the procedure name */
740 RtlStringCbCopyA(*MissingApi
,
741 MAXIMUM_FILENAME_LENGTH
,
742 (PCHAR
)&NameImport
->Name
[0]);
744 /* Setup name tables */
745 DPRINT("Import name: %s\n", NameImport
->Name
);
746 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
747 ExportDirectory
->AddressOfNames
);
748 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
749 ExportDirectory
->AddressOfNameOrdinals
);
751 /* Get the hint and check if it's valid */
752 Hint
= NameImport
->Hint
;
753 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
754 !(strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
756 /* We have a match, get the ordinal number from here */
757 Ordinal
= OrdinalTable
[Hint
];
761 /* Do a binary search */
762 High
= ExportDirectory
->NumberOfNames
- 1;
765 /* Get new middle value */
766 Mid
= (Low
+ High
) >> 1;
769 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
787 /* Check if we couldn't find it */
790 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport
->Name
);
791 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
794 /* Otherwise, this is the ordinal */
795 Ordinal
= OrdinalTable
[Mid
];
799 /* Check if the ordinal is invalid */
800 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
803 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
807 /* In case the forwarder is missing */
808 MissingForwarder
= NameBuffer
;
810 /* Resolve the address and write it */
811 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
812 ExportDirectory
->AddressOfFunctions
);
813 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
815 /* Assume success from now on */
816 Status
= STATUS_SUCCESS
;
818 /* Check if the function is actually a forwarder */
819 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
820 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
822 /* Now assume failure in case the forwarder doesn't exist */
823 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
825 /* Build the forwarder name */
826 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
827 DllName
.Length
= (USHORT
)(strchr(DllName
.Buffer
, '.') -
830 DllName
.MaximumLength
= DllName
.Length
;
833 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
837 /* We failed, just return an error */
841 /* Loop the module list */
842 NextEntry
= PsLoadedModuleList
.Flink
;
843 while (NextEntry
!= &PsLoadedModuleList
)
845 /* Get the loader entry */
846 LdrEntry
= CONTAINING_RECORD(NextEntry
,
847 LDR_DATA_TABLE_ENTRY
,
850 /* Check if it matches */
851 if (RtlPrefixUnicodeString(&ForwarderName
,
852 &LdrEntry
->BaseDllName
,
855 /* Get the forwarder export directory */
856 ForwardExportDirectory
=
857 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
859 IMAGE_DIRECTORY_ENTRY_EXPORT
,
861 if (!ForwardExportDirectory
) break;
863 /* Allocate a name entry */
864 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
866 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
867 sizeof(*ForwardName
) +
870 if (!ForwardName
) break;
873 RtlCopyMemory(&ForwardName
->Name
[0],
874 DllName
.Buffer
+ DllName
.Length
,
876 ForwardName
->Hint
= 0;
878 /* Set the new address */
879 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
881 /* Snap the forwarder */
882 Status
= MiSnapThunk(LdrEntry
->DllBase
,
886 ForwardExportDirectory
,
891 /* Free the forwarder name and set the thunk */
892 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
893 Address
->u1
= ForwardThunk
.u1
;
897 /* Go to the next entry */
898 NextEntry
= NextEntry
->Flink
;
902 RtlFreeUnicodeString(&ForwarderName
);
912 MmUnloadSystemImage(IN PVOID ImageHandle
)
914 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
915 PVOID BaseAddress
= LdrEntry
->DllBase
;
918 BOOLEAN HadEntry
= FALSE
;
920 /* Acquire the loader lock */
921 KeEnterCriticalRegion();
922 KeWaitForSingleObject(&MmSystemLoadLock
,
928 /* Check if this driver was loaded at boot and didn't get imports parsed */
929 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) goto Done
;
931 /* We should still be alive */
932 ASSERT(LdrEntry
->LoadCount
!= 0);
933 LdrEntry
->LoadCount
--;
935 /* Check if we're still loaded */
936 if (LdrEntry
->LoadCount
) goto Done
;
938 /* We should cleanup... are symbols loaded */
939 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
941 /* Create the ANSI name */
942 Status
= RtlUnicodeStringToAnsiString(&TempName
,
943 &LdrEntry
->BaseDllName
,
945 if (NT_SUCCESS(Status
))
947 /* Unload the symbols */
948 DbgUnLoadImageSymbols(&TempName
,
950 (ULONG_PTR
)PsGetCurrentProcessId());
951 RtlFreeAnsiString(&TempName
);
955 /* FIXME: Free the driver */
956 DPRINT1("Leaking driver: %wZ\n", &LdrEntry
->BaseDllName
);
957 //MmFreeSection(LdrEntry->DllBase);
959 /* Check if we're linked in */
960 if (LdrEntry
->InLoadOrderLinks
.Flink
)
963 MiProcessLoaderEntry(LdrEntry
, FALSE
);
967 /* Dereference and clear the imports */
968 MiDereferenceImports(LdrEntry
->LoadedImports
);
969 MiClearImports(LdrEntry
);
971 /* Check if the entry needs to go away */
974 /* Check if it had a name */
975 if (LdrEntry
->FullDllName
.Buffer
)
978 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
981 /* Check if we had a section */
982 if (LdrEntry
->SectionPointer
)
985 ObDereferenceObject(LdrEntry
->SectionPointer
);
989 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
992 /* Release the system lock and return */
994 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
995 KeLeaveCriticalRegion();
996 return STATUS_SUCCESS
;
1001 MiResolveImageReferences(IN PVOID ImageBase
,
1002 IN PUNICODE_STRING ImageFileDirectory
,
1003 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1004 OUT PCHAR
*MissingApi
,
1005 OUT PWCHAR
*MissingDriver
,
1006 OUT PLOAD_IMPORTS
*LoadImports
)
1008 static UNICODE_STRING DriversFolderName
= RTL_CONSTANT_STRING(L
"drivers\\");
1009 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
1010 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
1011 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
1012 PLOAD_IMPORTS LoadedImports
, NewImports
;
1013 ULONG GdiLink
, NormalLink
, i
;
1014 BOOLEAN ReferenceNeeded
, Loaded
;
1015 ANSI_STRING TempString
;
1016 UNICODE_STRING NameString
, DllName
;
1017 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
1018 PVOID ImportBase
, DllBase
;
1019 PLIST_ENTRY NextEntry
;
1020 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
1022 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
1024 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1025 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
1027 /* No name string buffer yet */
1028 NameString
.Buffer
= NULL
;
1030 /* Assume no imports */
1031 *LoadImports
= MM_SYSLDR_NO_IMPORTS
;
1033 /* Get the import descriptor */
1034 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
1036 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1038 if (!ImportDescriptor
) return STATUS_SUCCESS
;
1040 /* Loop all imports to count them */
1041 for (CurrentImport
= ImportDescriptor
;
1042 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
1049 /* Make sure we have non-zero imports */
1052 /* Calculate and allocate the list we'll need */
1053 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1054 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
1060 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
1061 LoadedImports
->Count
= ImportCount
;
1067 LoadedImports
= NULL
;
1070 /* Reset the import count and loop descriptors again */
1071 ImportCount
= GdiLink
= NormalLink
= 0;
1072 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
1075 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
1077 /* Check if this is a GDI driver */
1079 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
1081 /* We can also allow dxapi (for Windows compat, allow IRT and coverage) */
1082 NormalLink
= NormalLink
|
1083 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
1084 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)) &&
1085 (_strnicmp(ImportName
, "coverage", sizeof("coverage") - 1)) &&
1086 (_strnicmp(ImportName
, "irt", sizeof("irt") - 1)));
1088 /* Check if this is a valid GDI driver */
1089 if ((GdiLink
) && (NormalLink
))
1091 /* It's not, it's importing stuff it shouldn't be! */
1092 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1096 /* Check for user-mode printer or video card drivers, which don't belong */
1097 if (!(_strnicmp(ImportName
, "ntdll", sizeof("ntdll") - 1)) ||
1098 !(_strnicmp(ImportName
, "winsrv", sizeof("winsrv") - 1)) ||
1099 !(_strnicmp(ImportName
, "advapi32", sizeof("advapi32") - 1)) ||
1100 !(_strnicmp(ImportName
, "kernel32", sizeof("kernel32") - 1)) ||
1101 !(_strnicmp(ImportName
, "user32", sizeof("user32") - 1)) ||
1102 !(_strnicmp(ImportName
, "gdi32", sizeof("gdi32") - 1)))
1104 /* This is not kernel code */
1105 Status
= STATUS_PROCEDURE_NOT_FOUND
;
1109 /* Check if this is a "core" import, which doesn't get referenced */
1110 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1111 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1112 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1114 /* Don't reference this */
1115 ReferenceNeeded
= FALSE
;
1119 /* Reference these modules */
1120 ReferenceNeeded
= TRUE
;
1123 /* Now setup a unicode string for the import */
1124 RtlInitAnsiString(&TempString
, ImportName
);
1125 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1126 if (!NT_SUCCESS(Status
))
1132 /* We don't support name prefixes yet */
1133 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1135 /* Remember that we haven't loaded the import at this point */
1140 /* Loop the driver list */
1141 NextEntry
= PsLoadedModuleList
.Flink
;
1142 while (NextEntry
!= &PsLoadedModuleList
)
1144 /* Get the loader entry and compare the name */
1145 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1146 LDR_DATA_TABLE_ENTRY
,
1148 if (RtlEqualUnicodeString(&NameString
,
1149 &LdrEntry
->BaseDllName
,
1152 /* Get the base address */
1153 ImportBase
= LdrEntry
->DllBase
;
1155 /* Check if we haven't loaded yet, and we need references */
1156 if (!(Loaded
) && (ReferenceNeeded
))
1158 /* Make sure we're not already loading */
1159 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1161 /* Increase the load count */
1162 LdrEntry
->LoadCount
++;
1166 /* Done, break out */
1170 /* Go to the next entry */
1171 NextEntry
= NextEntry
->Flink
;
1174 /* Check if we haven't loaded the import yet */
1177 /* Setup the import DLL name */
1178 DllName
.MaximumLength
= NameString
.Length
+
1179 ImageFileDirectory
->Length
+
1180 sizeof(UNICODE_NULL
);
1181 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1182 DllName
.MaximumLength
,
1184 if (!DllName
.Buffer
)
1186 /* We're out of resources */
1187 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1191 /* Add the import name to the base directory */
1192 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1193 RtlAppendUnicodeStringToString(&DllName
,
1196 /* Load the image */
1197 Status
= MmLoadSystemImage(&DllName
,
1204 /* win32k / GDI drivers can also import from system32 folder */
1205 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) &&
1206 (MI_IS_SESSION_ADDRESS(ImageBase
) || 1)) // HACK
1208 /* Free the old name buffer */
1209 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1211 /* Calculate size for a string the adds 'drivers\' */
1212 DllName
.MaximumLength
+= DriversFolderName
.Length
;
1214 /* Allocate the new buffer */
1215 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1216 DllName
.MaximumLength
,
1218 if (!DllName
.Buffer
)
1220 /* We're out of resources */
1221 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1225 /* Copy image directory and append 'drivers\' folder name */
1226 RtlCopyUnicodeString(&DllName
, ImageFileDirectory
);
1227 RtlAppendUnicodeStringToString(&DllName
, &DriversFolderName
);
1229 /* Now add the import name */
1230 RtlAppendUnicodeStringToString(&DllName
, &NameString
);
1232 /* Try once again to load the image */
1233 Status
= MmLoadSystemImage(&DllName
,
1241 if (!NT_SUCCESS(Status
))
1243 /* Fill out the information for the error */
1244 *MissingDriver
= DllName
.Buffer
;
1245 *(PULONG
)MissingDriver
|= 1;
1248 DPRINT1("Failed to load dependency: %wZ\n", &DllName
);
1250 /* Don't free the name */
1251 DllName
.Buffer
= NULL
;
1253 /* Cleanup and return */
1257 /* We can free the DLL Name */
1258 ExFreePoolWithTag(DllName
.Buffer
, TAG_LDR_WSTR
);
1259 DllName
.Buffer
= NULL
;
1261 /* We're now loaded */
1265 ASSERT(DllBase
== DllEntry
->DllBase
);
1267 /* Call the initialization routines */
1268 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1269 if (!NT_SUCCESS(Status
))
1271 /* We failed, unload the image */
1272 MmUnloadSystemImage(DllEntry
);
1273 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status
);
1277 /* Loop again to make sure that everything is OK */
1281 /* Check if we're support to reference this import */
1282 if ((ReferenceNeeded
) && (LoadedImports
))
1284 /* Make sure we're not already loading */
1285 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1288 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1293 /* Free the import name */
1294 RtlFreeUnicodeString(&NameString
);
1296 /* Set the missing driver name and get the export directory */
1297 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1298 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1300 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1302 if (!ExportDirectory
)
1304 /* Cleanup and return */
1305 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver
);
1306 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1310 /* Make sure we have an IAT */
1311 if (ImportDescriptor
->OriginalFirstThunk
)
1313 /* Get the first thunks */
1314 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1315 ImportDescriptor
->OriginalFirstThunk
);
1316 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1317 ImportDescriptor
->FirstThunk
);
1320 while (OrigThunk
->u1
.AddressOfData
)
1323 Status
= MiSnapThunk(ImportBase
,
1331 if (!NT_SUCCESS(Status
))
1333 /* Cleanup and return */
1337 /* Reset the buffer */
1338 *MissingApi
= MissingApiBuffer
;
1342 /* Go to the next import */
1346 /* Check if we have an import list */
1349 /* Reset the count again, and loop entries */
1351 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1353 if (LoadedImports
->Entry
[i
])
1355 /* Got an entry, OR it with 1 in case it's the single entry */
1356 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] |
1357 MM_SYSLDR_SINGLE_ENTRY
);
1362 /* Check if we had no imports */
1365 /* Free the list and set it to no imports */
1366 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1367 LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1369 else if (ImportCount
== 1)
1371 /* Just one entry, we can free the table and only use our entry */
1372 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1373 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1375 else if (ImportCount
!= LoadedImports
->Count
)
1377 /* Allocate a new list */
1378 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1379 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1385 NewImports
->Count
= 0;
1387 /* Loop all the imports */
1388 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1390 /* Make sure it's valid */
1391 if (LoadedImports
->Entry
[i
])
1394 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1395 NewImports
->Count
++;
1399 /* Free the old copy */
1400 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1401 LoadedImports
= NewImports
;
1405 /* Return the list */
1406 *LoadImports
= LoadedImports
;
1409 /* Return success */
1410 return STATUS_SUCCESS
;
1414 /* Cleanup and return */
1415 RtlFreeUnicodeString(&NameString
);
1419 MiDereferenceImports(LoadedImports
);
1420 ExFreePoolWithTag(LoadedImports
, TAG_LDR_IMPORTS
);
1428 MiFreeInitializationCode(IN PVOID InitStart
,
1432 PFN_NUMBER PagesFreed
;
1434 /* Get the start PTE */
1435 PointerPte
= MiAddressToPte(InitStart
);
1436 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart
) == FALSE
);
1438 /* Compute the number of pages we expect to free */
1439 PagesFreed
= (PFN_NUMBER
)(MiAddressToPte(InitEnd
) - PointerPte
);
1441 /* Try to actually free them */
1442 PagesFreed
= MiDeleteSystemPageableVm(PointerPte
,
1451 MiFindInitializationCode(OUT PVOID
*StartVa
,
1454 ULONG Size
, SectionCount
, Alignment
;
1455 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1456 ULONG_PTR DllBase
, InitStart
, InitEnd
, ImageEnd
, InitCode
;
1457 PLIST_ENTRY NextEntry
;
1458 PIMAGE_NT_HEADERS NtHeader
;
1459 PIMAGE_SECTION_HEADER Section
, LastSection
, InitSection
;
1461 DBG_UNREFERENCED_LOCAL_VARIABLE(InitSection
);
1463 /* So we don't free our own code yet */
1464 InitCode
= (ULONG_PTR
)&MiFindInitializationCode
;
1466 /* Assume failure */
1469 /* Acquire the necessary locks while we loop the list */
1470 KeEnterCriticalRegion();
1471 KeWaitForSingleObject(&MmSystemLoadLock
,
1476 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
1478 /* Loop all loaded modules */
1479 NextEntry
= PsLoadedModuleList
.Flink
;
1480 while (NextEntry
!= &PsLoadedModuleList
)
1482 /* Get the loader entry and its DLL base */
1483 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1484 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1486 /* Only process boot loaded images. Other drivers are processed by
1487 MmFreeDriverInitialization */
1488 if (LdrEntry
->Flags
& LDRP_MM_LOADED
)
1491 NextEntry
= NextEntry
->Flink
;
1495 /* Get the NT header */
1496 NtHeader
= RtlImageNtHeader((PVOID
)DllBase
);
1500 NextEntry
= NextEntry
->Flink
;
1504 /* Get the first section, the section count, and scan them all */
1505 Section
= IMAGE_FIRST_SECTION(NtHeader
);
1506 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
;
1508 while (SectionCount
> 0)
1510 /* Assume failure */
1513 /* Is this the INIT section or a discardable section? */
1514 if ((strncmp((PCCH
)Section
->Name
, "INIT", 5) == 0) ||
1515 ((Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)))
1519 InitSection
= Section
;
1524 /* Pick the biggest size -- either raw or virtual */
1525 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1527 /* Read the section alignment */
1528 Alignment
= NtHeader
->OptionalHeader
.SectionAlignment
;
1530 /* Get the start and end addresses */
1531 InitStart
= DllBase
+ Section
->VirtualAddress
;
1532 InitEnd
= ALIGN_UP_BY(InitStart
+ Size
, Alignment
);
1534 /* Align the addresses to PAGE_SIZE */
1535 InitStart
= ALIGN_UP_BY(InitStart
, PAGE_SIZE
);
1536 InitEnd
= ALIGN_DOWN_BY(InitEnd
, PAGE_SIZE
);
1538 /* Have we reached the last section? */
1539 if (SectionCount
== 1)
1542 LastSection
= Section
;
1546 /* We have not, loop all the sections */
1550 /* Keep going until we find a non-discardable section range */
1553 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1555 /* Discardable, so record it, then keep going */
1556 LastSection
= Section
;
1560 /* Non-contigous discard flag, or no flag, break out */
1564 while (SectionCount
> 1);
1567 /* Have we found a discardable or init section? */
1570 /* Pick the biggest size -- either raw or virtual */
1571 Size
= max(LastSection
->SizeOfRawData
, LastSection
->Misc
.VirtualSize
);
1573 /* Use this as the end of the section address */
1574 InitEnd
= DllBase
+ LastSection
->VirtualAddress
+ Size
;
1576 /* Have we reached the last section yet? */
1577 if (SectionCount
!= 1)
1579 /* Then align this accross the session boundary */
1580 InitEnd
= ALIGN_UP_BY(InitEnd
, Alignment
);
1581 InitEnd
= ALIGN_DOWN_BY(InitEnd
, PAGE_SIZE
);
1585 /* Make sure we don't let the init section go past the image */
1586 ImageEnd
= DllBase
+ LdrEntry
->SizeOfImage
;
1587 if (InitEnd
> ImageEnd
) InitEnd
= ALIGN_UP_BY(ImageEnd
, PAGE_SIZE
);
1589 /* Make sure we have a valid, non-zero init section */
1590 if (InitStart
< InitEnd
)
1592 /* Make sure we are not within this code itself */
1593 if ((InitCode
>= InitStart
) && (InitCode
< InitEnd
))
1595 /* Return it, we can't free ourselves now */
1596 ASSERT(*StartVa
== 0);
1597 *StartVa
= (PVOID
)InitStart
;
1598 *EndVa
= (PVOID
)InitEnd
;
1602 /* This isn't us -- go ahead and free it */
1603 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID
)InitStart
) == FALSE
);
1604 DPRINT("Freeing init code: %p-%p ('%wZ' @%p : '%s')\n",
1607 &LdrEntry
->BaseDllName
,
1610 MiFreeInitializationCode((PVOID
)InitStart
, (PVOID
)InitEnd
);
1615 /* Move to the next section */
1620 /* Move to the next module */
1621 NextEntry
= NextEntry
->Flink
;
1624 /* Release the locks and return */
1625 ExReleaseResourceLite(&PsLoadedModuleResource
);
1626 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1627 KeLeaveCriticalRegion();
1631 * Note: This function assumes that all discardable sections are at the end of
1632 * the PE file. It searches backwards until it finds the non-discardable section
1636 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1638 PMMPTE StartPte
, EndPte
;
1639 PFN_NUMBER PageCount
;
1642 PIMAGE_NT_HEADERS NtHeader
;
1643 PIMAGE_SECTION_HEADER Section
, DiscardSection
;
1645 /* Get the base address and the page count */
1646 DllBase
= LdrEntry
->DllBase
;
1647 PageCount
= LdrEntry
->SizeOfImage
>> PAGE_SHIFT
;
1649 /* Get the last PTE in this image */
1650 EndPte
= MiAddressToPte(DllBase
) + PageCount
;
1652 /* Get the NT header */
1653 NtHeader
= RtlImageNtHeader(DllBase
);
1654 if (!NtHeader
) return;
1656 /* Get the last section and loop each section backwards */
1657 Section
= IMAGE_FIRST_SECTION(NtHeader
) + NtHeader
->FileHeader
.NumberOfSections
;
1658 DiscardSection
= NULL
;
1659 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
1661 /* Go back a section and check if it's discardable */
1663 if (Section
->Characteristics
& IMAGE_SCN_MEM_DISCARDABLE
)
1665 /* It is, select it for freeing */
1666 DiscardSection
= Section
;
1670 /* No more discardable sections exist, bail out */
1675 /* Bail out if there's nothing to free */
1676 if (!DiscardSection
) return;
1678 /* Push the DLL base to the first disacrable section, and get its PTE */
1679 DllBase
= (PVOID
)ROUND_TO_PAGES((ULONG_PTR
)DllBase
+ DiscardSection
->VirtualAddress
);
1680 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase
) == FALSE
);
1681 StartPte
= MiAddressToPte(DllBase
);
1683 /* Check how many pages to free total */
1684 PageCount
= (PFN_NUMBER
)(EndPte
- StartPte
);
1685 if (!PageCount
) return;
1687 /* Delete this many PTEs */
1688 MiDeleteSystemPageableVm(StartPte
, PageCount
, 0, NULL
);
1694 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1696 PLIST_ENTRY NextEntry
;
1698 PIMAGE_NT_HEADERS NtHeader
;
1699 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1700 PIMAGE_FILE_HEADER FileHeader
;
1701 BOOLEAN ValidRelocs
;
1702 PIMAGE_DATA_DIRECTORY DataDirectory
;
1703 PVOID DllBase
, NewImageAddress
;
1705 PMMPTE PointerPte
, StartPte
, LastPte
;
1708 MMPTE TempPte
, OldPte
;
1710 /* Loop driver list */
1711 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1712 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1713 NextEntry
= NextEntry
->Flink
)
1715 /* Get the loader entry and NT header */
1716 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1717 LDR_DATA_TABLE_ENTRY
,
1719 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1722 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1724 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1725 &LdrEntry
->FullDllName
);
1727 /* Get the first PTE and the number of PTEs we'll need */
1728 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1729 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1730 LastPte
= StartPte
+ PteCount
;
1734 while (PointerPte
< LastPte
)
1737 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1738 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1739 len
= wcslen(LdrEntry
->BaseDllName
.Buffer
) * sizeof(WCHAR
);
1740 snprintf(Pfn1
->ProcessName
, min(16, len
), "%S", LdrEntry
->BaseDllName
.Buffer
);
1744 /* Skip kernel and HAL */
1745 /* ROS HACK: Skip BOOTVID/KDCOM too */
1747 if (i
<= 4) continue;
1749 /* Skip non-drivers */
1750 if (!NtHeader
) continue;
1752 /* Get the file header and make sure we can relocate */
1753 FileHeader
= &NtHeader
->FileHeader
;
1754 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1755 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1756 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1758 /* Everything made sense until now, check the relocation section too */
1759 DataDirectory
= &NtHeader
->OptionalHeader
.
1760 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1761 if (!DataDirectory
->VirtualAddress
)
1763 /* We don't really have relocations */
1764 ValidRelocs
= FALSE
;
1768 /* Make sure the size is valid */
1769 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1770 LdrEntry
->SizeOfImage
)
1772 /* They're not, skip */
1776 /* We have relocations */
1780 /* Remember the original address */
1781 DllBase
= LdrEntry
->DllBase
;
1784 PointerPte
= StartPte
;
1785 while (PointerPte
< LastPte
)
1787 /* Mark the page modified in the PFN database */
1788 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1789 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1790 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1791 Pfn1
->u3
.e1
.Modified
= TRUE
;
1797 /* Now reserve system PTEs for the image */
1798 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1801 /* Shouldn't happen */
1802 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
1806 /* This is the new virtual address for the module */
1807 LastPte
= PointerPte
+ PteCount
;
1808 NewImageAddress
= MiPteToAddress(PointerPte
);
1811 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1812 ASSERT(ExpInitializationPhase
== 0);
1814 /* Loop the new driver PTEs */
1815 TempPte
= ValidKernelPte
;
1816 while (PointerPte
< LastPte
)
1818 /* Copy the old data */
1820 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1822 /* Set page number from the loader's memory */
1823 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1826 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1833 /* Update position */
1834 PointerPte
-= PteCount
;
1837 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1839 /* Set the image base to the address where the loader put it */
1840 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1842 /* Check if we had relocations */
1845 /* Relocate the image */
1846 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1850 STATUS_CONFLICTING_ADDRESSES
,
1851 STATUS_INVALID_IMAGE_FORMAT
);
1852 if (!NT_SUCCESS(Status
))
1854 /* This shouldn't happen */
1855 ERROR_FATAL("Relocations failed!\n");
1860 /* Update the loader entry */
1861 LdrEntry
->DllBase
= NewImageAddress
;
1863 /* Update the thunks */
1864 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1865 MiUpdateThunks(LoaderBlock
,
1868 LdrEntry
->SizeOfImage
);
1870 /* Update the loader entry */
1871 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1872 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1873 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1874 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1876 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1883 MiBuildImportsForBootDrivers(VOID
)
1885 PLIST_ENTRY NextEntry
, NextEntry2
;
1886 PLDR_DATA_TABLE_ENTRY LdrEntry
, KernelEntry
, HalEntry
, LdrEntry2
, LastEntry
;
1887 PLDR_DATA_TABLE_ENTRY
* EntryArray
;
1888 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1889 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1890 PLOAD_IMPORTS LoadedImports
;
1891 ULONG LoadedImportsSize
, ImportSize
;
1892 PULONG_PTR ImageThunk
;
1893 ULONG_PTR DllBase
, DllEnd
;
1894 ULONG Modules
= 0, i
, j
= 0;
1895 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
1897 /* Initialize variables */
1898 KernelEntry
= HalEntry
= LastEntry
= NULL
;
1900 /* Loop the loaded module list... we are early enough that no lock is needed */
1901 NextEntry
= PsLoadedModuleList
.Flink
;
1902 while (NextEntry
!= &PsLoadedModuleList
)
1905 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1906 LDR_DATA_TABLE_ENTRY
,
1909 /* Check if it's the kernel or HAL */
1910 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1913 KernelEntry
= LdrEntry
;
1915 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1918 HalEntry
= LdrEntry
;
1921 /* Check if this is a driver DLL */
1922 if (LdrEntry
->Flags
& LDRP_DRIVER_DEPENDENT_DLL
)
1924 /* Check if this is the HAL or kernel */
1925 if ((LdrEntry
== HalEntry
) || (LdrEntry
== KernelEntry
))
1927 /* Add a reference */
1928 LdrEntry
->LoadCount
= 1;
1932 /* No referencing needed */
1933 LdrEntry
->LoadCount
= 0;
1938 /* Add a reference for all other modules as well */
1939 LdrEntry
->LoadCount
= 1;
1942 /* Remember this came from the loader */
1943 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
1946 NextEntry
= NextEntry
->Flink
;
1950 /* We must have at least found the kernel and HAL */
1951 if (!(HalEntry
) || (!KernelEntry
)) return STATUS_NOT_FOUND
;
1953 /* Allocate the list */
1954 EntryArray
= ExAllocatePoolWithTag(PagedPool
, Modules
* sizeof(PVOID
), TAG_LDR_IMPORTS
);
1955 if (!EntryArray
) return STATUS_INSUFFICIENT_RESOURCES
;
1957 /* Loop the loaded module list again */
1958 NextEntry
= PsLoadedModuleList
.Flink
;
1959 while (NextEntry
!= &PsLoadedModuleList
)
1962 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1963 LDR_DATA_TABLE_ENTRY
,
1965 #ifdef _WORKING_LOADER_
1966 /* Get its imports */
1967 ImageThunk
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1969 IMAGE_DIRECTORY_ENTRY_IAT
,
1973 /* Get its imports */
1974 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1976 IMAGE_DIRECTORY_ENTRY_IMPORT
,
1978 if (!ImportDescriptor
)
1982 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
1983 NextEntry
= NextEntry
->Flink
;
1987 /* Clear the list and count the number of IAT thunks */
1988 RtlZeroMemory(EntryArray
, Modules
* sizeof(PVOID
));
1989 #ifdef _WORKING_LOADER_
1990 ImportSize
/= sizeof(ULONG_PTR
);
1992 /* Scan the thunks */
1993 for (i
= 0, DllBase
= 0, DllEnd
= 0; i
< ImportSize
; i
++, ImageThunk
++)
1995 DllBase
= DllEnd
= i
= 0;
1996 while ((ImportDescriptor
->Name
) &&
1997 (ImportDescriptor
->OriginalFirstThunk
))
1999 /* Get the image thunk */
2000 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
2001 ImportDescriptor
->FirstThunk
);
2005 /* Do we already have an address? */
2008 /* Is the thunk in the same address? */
2009 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
2011 /* Skip it, we already have a reference for it */
2012 ASSERT(EntryArray
[j
]);
2018 /* Loop the loaded module list to locate this address owner */
2020 NextEntry2
= PsLoadedModuleList
.Flink
;
2021 while (NextEntry2
!= &PsLoadedModuleList
)
2024 LdrEntry2
= CONTAINING_RECORD(NextEntry2
,
2025 LDR_DATA_TABLE_ENTRY
,
2028 /* Get the address range for this module */
2029 DllBase
= (ULONG_PTR
)LdrEntry2
->DllBase
;
2030 DllEnd
= DllBase
+ LdrEntry2
->SizeOfImage
;
2032 /* Check if this IAT entry matches it */
2033 if ((*ImageThunk
>= DllBase
) && (*ImageThunk
< DllEnd
))
2036 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
2037 EntryArray
[j
] = LdrEntry2
;
2041 /* Keep searching */
2042 NextEntry2
= NextEntry2
->Flink
;
2046 /* Do we have a thunk outside the range? */
2047 if ((*ImageThunk
< DllBase
) || (*ImageThunk
>= DllEnd
))
2052 /* Should not be happening */
2053 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
2054 LdrEntry
, ImageThunk
, *ImageThunk
);
2057 /* Reset if we hit this */
2060 #ifndef _WORKING_LOADER_
2069 /* Now scan how many imports we really have */
2070 for (i
= 0, ImportSize
= 0; i
< Modules
; i
++)
2072 /* Skip HAL and kernel */
2073 if ((EntryArray
[i
]) &&
2074 (EntryArray
[i
] != HalEntry
) &&
2075 (EntryArray
[i
] != KernelEntry
))
2077 /* A valid reference */
2078 LastEntry
= EntryArray
[i
];
2083 /* Do we have any imports after all? */
2087 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2089 else if (ImportSize
== 1)
2091 /* A single entry import */
2092 LdrEntry
->LoadedImports
= (PVOID
)((ULONG_PTR
)LastEntry
| MM_SYSLDR_SINGLE_ENTRY
);
2093 LastEntry
->LoadCount
++;
2097 /* We need an import table */
2098 LoadedImportsSize
= ImportSize
* sizeof(PVOID
) + sizeof(SIZE_T
);
2099 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
2102 ASSERT(LoadedImports
);
2104 /* Save the count */
2105 LoadedImports
->Count
= ImportSize
;
2107 /* Now copy all imports */
2108 for (i
= 0, j
= 0; i
< Modules
; i
++)
2110 /* Skip HAL and kernel */
2111 if ((EntryArray
[i
]) &&
2112 (EntryArray
[i
] != HalEntry
) &&
2113 (EntryArray
[i
] != KernelEntry
))
2115 /* A valid reference */
2116 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2117 LoadedImports
->Entry
[j
] = EntryArray
[i
];
2118 EntryArray
[i
]->LoadCount
++;
2123 /* Should had as many entries as we expected */
2124 ASSERT(j
== ImportSize
);
2125 LdrEntry
->LoadedImports
= LoadedImports
;
2129 NextEntry
= NextEntry
->Flink
;
2132 /* Free the initial array */
2133 ExFreePoolWithTag(EntryArray
, TAG_LDR_IMPORTS
);
2135 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2137 /* Kernel and HAL are loaded at boot */
2138 KernelEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2139 HalEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
2141 /* All worked well */
2142 return STATUS_SUCCESS
;
2148 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2151 PIMAGE_NT_HEADERS NtHeaders
;
2152 PIMAGE_SECTION_HEADER SectionHeader
;
2153 ULONG Sections
, Size
;
2155 /* Get the kernel section header */
2156 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2157 NtHeaders
= RtlImageNtHeader((PVOID
)DllBase
);
2158 SectionHeader
= IMAGE_FIRST_SECTION(NtHeaders
);
2160 /* Loop all the sections */
2161 for (Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2162 Sections
> 0; --Sections
, ++SectionHeader
)
2164 /* Grab the size of the section */
2165 Size
= max(SectionHeader
->SizeOfRawData
, SectionHeader
->Misc
.VirtualSize
);
2167 /* Check for .RSRC section */
2168 if (*(PULONG
)SectionHeader
->Name
== 'rsr.')
2170 /* Remember the PTEs so we can modify them later */
2171 MiKernelResourceStartPte
= MiAddressToPte(DllBase
+
2172 SectionHeader
->VirtualAddress
);
2173 MiKernelResourceEndPte
= MiAddressToPte(ROUND_TO_PAGES(DllBase
+
2174 SectionHeader
->VirtualAddress
+ Size
));
2176 else if (*(PULONG
)SectionHeader
->Name
== 'LOOP')
2178 /* POOLCODE vs. POOLMI */
2179 if (*(PULONG
)&SectionHeader
->Name
[4] == 'EDOC')
2181 /* Found Ex* Pool code */
2182 ExPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2183 ExPoolCodeEnd
= ExPoolCodeStart
+ Size
;
2185 else if (*(PUSHORT
)&SectionHeader
->Name
[4] == 'MI')
2187 /* Found Mm* Pool code */
2188 MmPoolCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2189 MmPoolCodeEnd
= MmPoolCodeStart
+ Size
;
2192 else if ((*(PULONG
)SectionHeader
->Name
== 'YSIM') &&
2193 (*(PULONG
)&SectionHeader
->Name
[4] == 'ETPS'))
2195 /* Found MISYSPTE (Mm System PTE code) */
2196 MmPteCodeStart
= DllBase
+ SectionHeader
->VirtualAddress
;
2197 MmPteCodeEnd
= MmPteCodeStart
+ Size
;
2205 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
2207 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
2208 PLIST_ENTRY ListHead
, NextEntry
;
2211 /* Setup the loaded module list and locks */
2212 ExInitializeResourceLite(&PsLoadedModuleResource
);
2213 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
2214 InitializeListHead(&PsLoadedModuleList
);
2216 /* Get loop variables and the kernel entry */
2217 ListHead
= &LoaderBlock
->LoadOrderListHead
;
2218 NextEntry
= ListHead
->Flink
;
2219 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2220 LDR_DATA_TABLE_ENTRY
,
2222 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2224 /* Locate resource section, pool code, and system pte code */
2225 MiLocateKernelSections(LdrEntry
);
2227 /* Loop the loader block */
2228 while (NextEntry
!= ListHead
)
2230 /* Get the loader entry */
2231 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2232 LDR_DATA_TABLE_ENTRY
,
2235 /* FIXME: ROS HACK. Make sure this is a driver */
2236 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
2238 /* Skip this entry */
2239 NextEntry
= NextEntry
->Flink
;
2243 /* Calculate the size we'll need and allocate a copy */
2244 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2245 LdrEntry
->BaseDllName
.MaximumLength
+
2246 sizeof(UNICODE_NULL
);
2247 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2248 if (!NewEntry
) return FALSE
;
2250 /* Copy the entry over */
2251 *NewEntry
= *LdrEntry
;
2253 /* Allocate the name */
2254 NewEntry
->FullDllName
.Buffer
=
2255 ExAllocatePoolWithTag(PagedPool
,
2256 LdrEntry
->FullDllName
.MaximumLength
+
2257 sizeof(UNICODE_NULL
),
2259 if (!NewEntry
->FullDllName
.Buffer
)
2261 ExFreePoolWithTag(NewEntry
, TAG_MODULE_OBJECT
);
2265 /* Set the base name */
2266 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
2268 /* Copy the full and base name */
2269 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
2270 LdrEntry
->FullDllName
.Buffer
,
2271 LdrEntry
->FullDllName
.MaximumLength
);
2272 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
2273 LdrEntry
->BaseDllName
.Buffer
,
2274 LdrEntry
->BaseDllName
.MaximumLength
);
2276 /* Null-terminate the base name */
2277 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
2278 sizeof(WCHAR
)] = UNICODE_NULL
;
2280 /* Insert the entry into the list */
2281 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
2282 NextEntry
= NextEntry
->Flink
;
2285 /* Build the import lists for the boot drivers */
2286 MiBuildImportsForBootDrivers();
2294 MmChangeKernelResourceSectionProtection(IN ULONG_PTR ProtectionMask
)
2299 /* Don't do anything if the resource section is already writable */
2300 if (MiKernelResourceStartPte
== NULL
|| MiKernelResourceEndPte
== NULL
)
2303 /* If the resource section is physical, we cannot change its protection */
2304 if (MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(MiKernelResourceStartPte
)))
2308 for (PointerPte
= MiKernelResourceStartPte
; PointerPte
< MiKernelResourceEndPte
; ++PointerPte
)
2311 TempPte
= *PointerPte
;
2313 /* Update the protection */
2314 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte
, PointerPte
, ProtectionMask
, TempPte
.u
.Hard
.PageFrameNumber
);
2315 MI_UPDATE_VALID_PTE(PointerPte
, TempPte
);
2318 /* Only flush the current processor's TLB */
2325 MmMakeKernelResourceSectionWritable(VOID
)
2327 /* Don't do anything if the resource section is already writable */
2328 if (MiKernelResourceStartPte
== NULL
|| MiKernelResourceEndPte
== NULL
)
2331 /* If the resource section is physical, we cannot change its protection */
2332 if (MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(MiKernelResourceStartPte
)))
2335 if (MmChangeKernelResourceSectionProtection(MM_READWRITE
))
2338 * Invalidate the cached resource section PTEs
2339 * so as to not change its protection again later.
2341 MiKernelResourceStartPte
= NULL
;
2342 MiKernelResourceEndPte
= NULL
;
2348 MiUseLargeDriverPage(IN ULONG NumberOfPtes
,
2349 IN OUT PVOID
*ImageBaseAddress
,
2350 IN PUNICODE_STRING BaseImageName
,
2351 IN BOOLEAN BootDriver
)
2353 PLIST_ENTRY NextEntry
;
2354 BOOLEAN DriverFound
= FALSE
;
2355 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry
;
2356 ASSERT(KeGetCurrentIrql () <= APC_LEVEL
);
2357 ASSERT(*ImageBaseAddress
>= MmSystemRangeStart
);
2360 if (!(KeFeatureBits
& KF_LARGE_PAGE
)) return FALSE
;
2361 if (!(__readcr4() & CR4_PSE
)) return FALSE
;
2364 /* Make sure there's enough system PTEs for a large page driver */
2365 if (MmTotalFreeSystemPtes
[SystemPteSpace
] < (16 * (PDE_MAPPED_VA
>> PAGE_SHIFT
)))
2370 /* This happens if the registry key had a "*" (wildcard) in it */
2371 if (MiLargePageAllDrivers
== 0)
2373 /* It didn't, so scan the list */
2374 NextEntry
= MiLargePageDriverList
.Flink
;
2375 while (NextEntry
!= &MiLargePageDriverList
)
2377 /* Check if the driver name matches */
2378 LargePageDriverEntry
= CONTAINING_RECORD(NextEntry
,
2379 MI_LARGE_PAGE_DRIVER_ENTRY
,
2381 if (RtlEqualUnicodeString(BaseImageName
,
2382 &LargePageDriverEntry
->BaseName
,
2385 /* Enable large pages for this driver */
2391 NextEntry
= NextEntry
->Flink
;
2394 /* If we didn't find the driver, it doesn't need large pages */
2395 if (DriverFound
== FALSE
) return FALSE
;
2398 /* Nothing to do yet */
2399 DPRINT1("Large pages not supported!\n");
2405 MiSetSystemCodeProtection(
2406 _In_ PMMPTE FirstPte
,
2407 _In_ PMMPTE LastPte
,
2408 _In_ ULONG Protection
)
2414 for (PointerPte
= FirstPte
; PointerPte
<= LastPte
; PointerPte
++)
2417 TempPte
= *PointerPte
;
2419 /* Make sure it's valid */
2420 if (TempPte
.u
.Hard
.Valid
!= 1)
2422 DPRINT1("CORE-16449: FirstPte=%p, LastPte=%p, Protection=%lx\n", FirstPte
, LastPte
, Protection
);
2423 DPRINT1("CORE-16449: PointerPte=%p, TempPte=%lx\n", PointerPte
, TempPte
.u
.Long
);
2424 DPRINT1("CORE-16449: Please issue the 'mod' and 'bt' (KDBG) or 'lm' and 'kp' (WinDbg) commands. Then report this in Jira.\n");
2425 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
2429 /* Update the protection */
2430 TempPte
.u
.Hard
.Write
= BooleanFlagOn(Protection
, IMAGE_SCN_MEM_WRITE
);
2431 #if _MI_HAS_NO_EXECUTE
2432 TempPte
.u
.Hard
.NoExecute
= !BooleanFlagOn(Protection
, IMAGE_SCN_MEM_EXECUTE
);
2435 MI_UPDATE_VALID_PTE(PointerPte
, TempPte
);
2439 KeFlushEntireTb(TRUE
, TRUE
);
2446 MiWriteProtectSystemImage(
2447 _In_ PVOID ImageBase
)
2449 PIMAGE_NT_HEADERS NtHeaders
;
2450 PIMAGE_SECTION_HEADER SectionHeaders
, Section
;
2452 PVOID SectionBase
, SectionEnd
;
2455 PMMPTE FirstPte
, LastPte
;
2457 /* Check if the registry setting is on or not */
2458 if (MmEnforceWriteProtection
== FALSE
)
2460 /* Ignore section protection */
2464 /* Large page mapped images are not supported */
2465 NT_ASSERT(!MI_IS_PHYSICAL_ADDRESS(ImageBase
));
2467 /* Session images are not yet supported */
2468 NT_ASSERT(!MI_IS_SESSION_ADDRESS(ImageBase
));
2470 /* Get the NT headers */
2471 NtHeaders
= RtlImageNtHeader(ImageBase
);
2472 if (NtHeaders
== NULL
)
2474 DPRINT1("Failed to get NT headers for image @ %p\n", ImageBase
);
2478 /* Don't touch NT4 drivers */
2479 if ((NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) ||
2480 (NtHeaders
->OptionalHeader
.MajorSubsystemVersion
< 5))
2482 DPRINT1("Skipping NT 4 driver @ %p\n", ImageBase
);
2486 /* Get the section headers */
2487 SectionHeaders
= IMAGE_FIRST_SECTION(NtHeaders
);
2489 /* Get the base address of the first section */
2490 SectionBase
= Add2Ptr(ImageBase
, SectionHeaders
[0].VirtualAddress
);
2492 /* Start protecting the image header as R/O */
2493 FirstPte
= MiAddressToPte(ImageBase
);
2494 LastPte
= MiAddressToPte(SectionBase
) - 1;
2495 Protection
= IMAGE_SCN_MEM_READ
;
2496 if (LastPte
>= FirstPte
)
2498 MiSetSystemCodeProtection(FirstPte
, LastPte
, IMAGE_SCN_MEM_READ
);
2501 /* Loop the sections */
2502 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
2504 /* Get the section base address and size */
2505 Section
= &SectionHeaders
[i
];
2506 SectionBase
= Add2Ptr(ImageBase
, Section
->VirtualAddress
);
2507 SectionSize
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2509 /* Get the first PTE of this section */
2510 FirstPte
= MiAddressToPte(SectionBase
);
2512 /* Check for overlap with the previous range */
2513 if (FirstPte
== LastPte
)
2515 /* Combine the old and new protection by ORing them */
2516 Protection
|= (Section
->Characteristics
& IMAGE_SCN_PROTECTION_MASK
);
2518 /* Update the protection for this PTE */
2519 MiSetSystemCodeProtection(FirstPte
, FirstPte
, Protection
);
2525 /* There can not be gaps! */
2526 NT_ASSERT(FirstPte
== (LastPte
+ 1));
2528 /* Get the end of the section and the last PTE */
2529 SectionEnd
= Add2Ptr(SectionBase
, SectionSize
- 1);
2530 NT_ASSERT(SectionEnd
< Add2Ptr(ImageBase
, NtHeaders
->OptionalHeader
.SizeOfImage
));
2531 LastPte
= MiAddressToPte(SectionEnd
);
2533 /* If there are no more pages (after an overlap), skip this section */
2534 if (LastPte
< FirstPte
)
2536 NT_ASSERT(FirstPte
== (LastPte
+ 1));
2540 /* Get the section protection */
2541 Protection
= (Section
->Characteristics
& IMAGE_SCN_PROTECTION_MASK
);
2543 /* Update the protection for this section */
2544 MiSetSystemCodeProtection(FirstPte
, LastPte
, Protection
);
2547 /* Image should end with the last section */
2548 if (ALIGN_UP_POINTER_BY(SectionEnd
, PAGE_SIZE
) !=
2549 Add2Ptr(ImageBase
, NtHeaders
->OptionalHeader
.SizeOfImage
))
2551 DPRINT1("ImageBase 0x%p ImageSize 0x%lx Section %u VA 0x%lx Raw 0x%lx virt 0x%lx\n",
2553 NtHeaders
->OptionalHeader
.SizeOfImage
,
2555 Section
->VirtualAddress
,
2556 Section
->SizeOfRawData
,
2557 Section
->Misc
.VirtualSize
);
2563 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
2567 PETHREAD CurrentThread
= PsGetCurrentThread();
2568 PFN_COUNT PageCount
= 0;
2569 PFN_NUMBER PageFrameIndex
;
2573 /* The page fault handler is broken and doesn't page back in! */
2574 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
2577 /* Get the driver's base address */
2578 ImageBase
= MiPteToAddress(PointerPte
);
2579 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
2581 /* If this is a large page, it's stuck in physical memory */
2582 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
2584 /* Lock the working set */
2585 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2588 while (PointerPte
<= LastPte
)
2590 /* Check for valid PTE */
2591 if (PointerPte
->u
.Hard
.Valid
== 1)
2593 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
2594 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
2595 ASSERT(Pfn1
->u2
.ShareCount
== 1);
2597 /* No working sets in ReactOS yet */
2601 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
2605 /* Release the working set */
2606 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
2608 /* Do we have any driver pages? */
2611 /* Update counters */
2612 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
2618 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
2620 ULONG_PTR ImageBase
;
2621 PIMAGE_NT_HEADERS NtHeaders
;
2622 ULONG Sections
, Alignment
, Size
;
2623 PIMAGE_SECTION_HEADER Section
;
2624 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
2625 if (MmDisablePagingExecutive
) return;
2627 /* Get the driver base address and its NT header */
2628 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
2629 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
2630 if (!NtHeaders
) return;
2632 /* Get the sections and their alignment */
2633 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
2634 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
2636 /* Loop each section */
2637 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
2640 /* Find PAGE or .edata */
2641 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
2642 (*(PULONG
)Section
->Name
== 'ade.'))
2644 /* Had we already done some work? */
2647 /* Nope, setup the first PTE address */
2648 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
2649 Section
->VirtualAddress
));
2652 /* Compute the size */
2653 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
2655 /* Find the last PTE that maps this section */
2656 LastPte
= MiAddressToPte(ImageBase
+
2657 Section
->VirtualAddress
+
2658 Alignment
+ Size
- PAGE_SIZE
);
2662 /* Had we found a section before? */
2665 /* Mark it as pageable */
2666 MiSetPagingOfDriver(PointerPte
, LastPte
);
2671 /* Keep searching */
2676 /* Handle the straggler */
2677 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
2682 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
2684 PIMAGE_NT_HEADERS NtHeader
;
2687 /* Get NT Headers */
2688 NtHeader
= RtlImageNtHeader(BaseAddress
);
2691 /* Check if this image is only safe for UP while we have 2+ CPUs */
2692 if ((KeNumberProcessors
> 1) &&
2693 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
2700 /* Otherwise, it's safe */
2706 MmCheckSystemImage(IN HANDLE ImageHandle
,
2707 IN BOOLEAN PurgeSection
)
2710 HANDLE SectionHandle
;
2711 PVOID ViewBase
= NULL
;
2712 SIZE_T ViewSize
= 0;
2713 IO_STATUS_BLOCK IoStatusBlock
;
2714 FILE_STANDARD_INFORMATION FileStandardInfo
;
2715 KAPC_STATE ApcState
;
2716 PIMAGE_NT_HEADERS NtHeaders
;
2717 OBJECT_ATTRIBUTES ObjectAttributes
;
2720 /* Setup the object attributes */
2721 InitializeObjectAttributes(&ObjectAttributes
,
2723 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2727 /* Create a section for the DLL */
2728 Status
= ZwCreateSection(&SectionHandle
,
2729 SECTION_MAP_EXECUTE
,
2735 if (!NT_SUCCESS(Status
))
2737 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
2741 /* Make sure we're in the system process */
2742 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
2745 Status
= ZwMapViewOfSection(SectionHandle
,
2755 if (!NT_SUCCESS(Status
))
2757 /* We failed, close the handle and return */
2758 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status
);
2759 KeUnstackDetachProcess(&ApcState
);
2760 ZwClose(SectionHandle
);
2764 /* Now query image information */
2765 Status
= ZwQueryInformationFile(ImageHandle
,
2768 sizeof(FileStandardInfo
),
2769 FileStandardInformation
);
2770 if (NT_SUCCESS(Status
))
2772 /* First, verify the checksum */
2773 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2778 /* Set checksum failure */
2779 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2783 /* Make sure it's a real image */
2784 NtHeaders
= RtlImageNtHeader(ViewBase
);
2787 /* Set checksum failure */
2788 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2792 /* Make sure it's for the correct architecture */
2793 if ((NtHeaders
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_NATIVE
) ||
2794 (NtHeaders
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
))
2796 /* Set protection failure */
2797 Status
= STATUS_INVALID_IMAGE_PROTECT
;
2801 /* Check that it's a valid SMP image if we have more then one CPU */
2802 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2804 /* Otherwise it's not the right image */
2805 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2809 /* Unmap the section, close the handle, and return status */
2811 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2812 KeUnstackDetachProcess(&ApcState
);
2813 ZwClose(SectionHandle
);
2819 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2820 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2821 IN PUNICODE_STRING LoadedName OPTIONAL
,
2823 OUT PVOID
*ModuleObject
,
2824 OUT PVOID
*ImageBaseAddress
)
2826 PVOID ModuleLoadBase
= NULL
;
2828 HANDLE FileHandle
= NULL
;
2829 OBJECT_ATTRIBUTES ObjectAttributes
;
2830 IO_STATUS_BLOCK IoStatusBlock
;
2831 PIMAGE_NT_HEADERS NtHeader
;
2832 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2833 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2834 ULONG EntrySize
, DriverSize
;
2835 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2836 PCHAR MissingApiName
, Buffer
;
2837 PWCHAR MissingDriverName
;
2838 HANDLE SectionHandle
;
2839 ACCESS_MASK DesiredAccess
;
2840 PVOID Section
= NULL
;
2841 BOOLEAN LockOwned
= FALSE
;
2842 PLIST_ENTRY NextEntry
;
2843 IMAGE_INFO ImageInfo
;
2847 /* Detect session-load */
2851 ASSERT(NamePrefix
== NULL
);
2852 ASSERT(LoadedName
== NULL
);
2854 /* Make sure the process is in session too */
2855 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2858 /* Allocate a buffer we'll use for names */
2859 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
2860 MAXIMUM_FILENAME_LENGTH
,
2862 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2864 /* Check for a separator */
2865 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2870 /* Loop the path until we get to the base name */
2871 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2872 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2874 /* Get the length */
2875 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2876 BaseLength
*= sizeof(WCHAR
);
2878 /* Setup the string */
2879 BaseName
.Length
= (USHORT
)BaseLength
;
2880 BaseName
.Buffer
= p
;
2884 /* Otherwise, we already have a base name */
2885 BaseName
.Length
= FileName
->Length
;
2886 BaseName
.Buffer
= FileName
->Buffer
;
2889 /* Setup the maximum length */
2890 BaseName
.MaximumLength
= BaseName
.Length
;
2892 /* Now compute the base directory */
2893 BaseDirectory
= *FileName
;
2894 BaseDirectory
.Length
-= BaseName
.Length
;
2895 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2897 /* And the prefix, which for now is just the name itself */
2898 PrefixName
= *FileName
;
2900 /* Check if we have a prefix */
2901 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2903 /* Check if we already have a name, use it instead */
2904 if (LoadedName
) BaseName
= *LoadedName
;
2906 /* Check for loader snap debugging */
2907 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2909 /* Print out standard string */
2910 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2911 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2914 /* Acquire the load lock */
2916 ASSERT(LockOwned
== FALSE
);
2918 KeEnterCriticalRegion();
2919 KeWaitForSingleObject(&MmSystemLoadLock
,
2925 /* Scan the module list */
2926 NextEntry
= PsLoadedModuleList
.Flink
;
2927 while (NextEntry
!= &PsLoadedModuleList
)
2929 /* Get the entry and compare the names */
2930 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2931 LDR_DATA_TABLE_ENTRY
,
2933 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2935 /* Found it, break out */
2940 NextEntry
= NextEntry
->Flink
;
2943 /* Check if we found the image */
2944 if (NextEntry
!= &PsLoadedModuleList
)
2946 /* Check if we had already mapped a section */
2949 /* Dereference and clear */
2950 ObDereferenceObject(Section
);
2954 /* Check if this was supposed to be a session load */
2957 /* It wasn't, so just return the data */
2958 *ModuleObject
= LdrEntry
;
2959 *ImageBaseAddress
= LdrEntry
->DllBase
;
2960 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2964 /* We don't support session loading yet */
2965 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
2966 Status
= STATUS_NOT_IMPLEMENTED
;
2974 /* It wasn't loaded, and we didn't have a previous attempt */
2975 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2976 KeLeaveCriticalRegion();
2979 /* Check if KD is enabled */
2980 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2982 /* FIXME: Attempt to get image from KD */
2985 /* We don't have a valid entry */
2988 /* Setup image attributes */
2989 InitializeObjectAttributes(&ObjectAttributes
,
2991 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2995 /* Open the image */
2996 Status
= ZwOpenFile(&FileHandle
,
3000 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
3002 if (!NT_SUCCESS(Status
))
3004 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n",
3010 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
3011 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
3012 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
3013 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
3019 /* Check if this is a session-load */
3022 /* Then we only need read and execute */
3023 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
3027 /* Otherwise, we can allow write access */
3028 DesiredAccess
= SECTION_ALL_ACCESS
;
3031 /* Initialize the attributes for the section */
3032 InitializeObjectAttributes(&ObjectAttributes
,
3034 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3038 /* Create the section */
3039 Status
= ZwCreateSection(&SectionHandle
,
3046 if (!NT_SUCCESS(Status
))
3048 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status
);
3052 /* Now get the section pointer */
3053 Status
= ObReferenceObjectByHandle(SectionHandle
,
3054 SECTION_MAP_EXECUTE
,
3055 MmSectionObjectType
,
3059 ZwClose(SectionHandle
);
3060 if (!NT_SUCCESS(Status
)) goto Quickie
;
3062 /* Check if this was supposed to be a session-load */
3065 /* We don't support session loading yet */
3066 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
3070 /* Check the loader list again, we should end up in the path below */
3075 /* We don't have a valid entry */
3079 /* Load the image */
3080 Status
= MiLoadImageSection(&Section
,
3085 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
3087 /* Get the size of the driver */
3088 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageInformation
.ImageFileSize
;
3090 /* Make sure we're not being loaded into session space */
3093 /* Check for success */
3094 if (NT_SUCCESS(Status
))
3096 /* Support large pages for drivers */
3097 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
3103 /* Dereference the section */
3104 ObDereferenceObject(Section
);
3108 /* Check for failure of the load earlier */
3109 if (!NT_SUCCESS(Status
))
3111 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status
);
3115 /* Relocate the driver */
3116 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
3120 STATUS_CONFLICTING_ADDRESSES
,
3121 STATUS_INVALID_IMAGE_FORMAT
);
3122 if (!NT_SUCCESS(Status
))
3124 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status
);
3128 /* Get the NT Header */
3129 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
3131 /* Calculate the size we'll need for the entry and allocate it */
3132 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
3134 sizeof(UNICODE_NULL
);
3136 /* Allocate the entry */
3137 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
3141 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3145 /* Setup the entry */
3146 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
3147 LdrEntry
->LoadCount
= 1;
3148 LdrEntry
->LoadedImports
= LoadedImports
;
3149 LdrEntry
->PatchInformation
= NULL
;
3151 /* Check the version */
3152 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
3153 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
3155 /* Mark this image as a native image */
3156 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
3159 /* Setup the rest of the entry */
3160 LdrEntry
->DllBase
= ModuleLoadBase
;
3161 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
3162 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
3163 LdrEntry
->SizeOfImage
= DriverSize
;
3164 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
3165 LdrEntry
->SectionPointer
= Section
;
3167 /* Now write the DLL name */
3168 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
3169 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
3170 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
3172 /* Copy and null-terminate it */
3173 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
3176 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3178 /* Now allocate the full name */
3179 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
3181 sizeof(UNICODE_NULL
),
3183 if (!LdrEntry
->FullDllName
.Buffer
)
3185 /* Don't fail, just set it to zero */
3186 LdrEntry
->FullDllName
.Length
= 0;
3187 LdrEntry
->FullDllName
.MaximumLength
= 0;
3192 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
3193 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
3195 /* Copy and null-terminate */
3196 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
3199 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3203 MiProcessLoaderEntry(LdrEntry
, TRUE
);
3205 /* Resolve imports */
3206 MissingApiName
= Buffer
;
3207 MissingDriverName
= NULL
;
3208 Status
= MiResolveImageReferences(ModuleLoadBase
,
3214 if (!NT_SUCCESS(Status
))
3216 BOOLEAN NeedToFreeString
= FALSE
;
3218 /* If the lowest bit is set to 1, this is a hint that we need to free */
3219 if (*(ULONG_PTR
*)&MissingDriverName
& 1)
3221 NeedToFreeString
= TRUE
;
3222 *(ULONG_PTR
*)&MissingDriverName
&= ~1;
3225 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status
);
3226 DPRINT1(" Missing driver '%ls', missing API '%s'\n",
3227 MissingDriverName
, MissingApiName
);
3229 if (NeedToFreeString
)
3231 ExFreePoolWithTag(MissingDriverName
, TAG_LDR_WSTR
);
3235 MiProcessLoaderEntry(LdrEntry
, FALSE
);
3237 /* Check if we need to free the name */
3238 if (LdrEntry
->FullDllName
.Buffer
)
3241 ExFreePoolWithTag(LdrEntry
->FullDllName
.Buffer
, TAG_LDR_WSTR
);
3244 /* Free the entry itself */
3245 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
3250 /* Update the loader entry */
3251 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
3252 LDRP_ENTRY_PROCESSED
|
3254 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
3255 LdrEntry
->LoadedImports
= LoadedImports
;
3257 /* FIXME: Call driver verifier's loader function */
3259 /* Write-protect the system image */
3260 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
3262 /* Check if notifications are enabled */
3263 if (PsImageNotifyEnabled
)
3265 /* Fill out the notification data */
3266 ImageInfo
.Properties
= 0;
3267 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
3268 ImageInfo
.SystemModeImage
= TRUE
;
3269 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
3270 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
3271 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
3273 /* Send the notification */
3274 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
3277 #ifdef __ROS_ROSSYM__
3278 /* MiCacheImageSymbols doesn't detect rossym */
3281 /* Check if there's symbols */
3282 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
3285 /* Check if the system root is present */
3286 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
3287 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
3289 /* Add the system root */
3290 UnicodeTemp
= PrefixName
;
3291 UnicodeTemp
.Buffer
+= 11;
3292 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
3295 &SharedUserData
->NtSystemRoot
[2],
3300 /* Build the name */
3301 sprintf_nt(Buffer
, "%wZ", &BaseName
);
3304 /* Setup the ansi string */
3305 RtlInitString(&AnsiTemp
, Buffer
);
3307 /* Notify the debugger */
3308 DbgLoadImageSymbols(&AnsiTemp
,
3310 (ULONG_PTR
)PsGetCurrentProcessId());
3311 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
3314 /* Page the driver */
3315 ASSERT(Section
== NULL
);
3316 MiEnablePagingOfDriver(LdrEntry
);
3318 /* Return pointers */
3319 *ModuleObject
= LdrEntry
;
3320 *ImageBaseAddress
= LdrEntry
->DllBase
;
3323 /* Check if we have the lock acquired */
3326 /* Release the lock */
3327 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
3328 KeLeaveCriticalRegion();
3332 /* If we have a file handle, close it */
3333 if (FileHandle
) ZwClose(FileHandle
);
3335 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3336 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3338 /* Free the name buffer and return status */
3339 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
3343 PLDR_DATA_TABLE_ENTRY
3345 MiLookupDataTableEntry(IN PVOID Address
)
3347 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
3348 PLIST_ENTRY NextEntry
;
3352 NextEntry
= PsLoadedModuleList
.Flink
;
3355 /* Get the loader entry */
3356 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3357 LDR_DATA_TABLE_ENTRY
,
3360 /* Check if the address matches */
3361 if ((Address
>= LdrEntry
->DllBase
) &&
3362 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
3363 LdrEntry
->SizeOfImage
)))
3366 FoundEntry
= LdrEntry
;
3371 NextEntry
= NextEntry
->Flink
;
3372 } while(NextEntry
!= &PsLoadedModuleList
);
3374 /* Return the entry */
3378 /* PUBLIC FUNCTIONS ***********************************************************/
3385 MmPageEntireDriver(IN PVOID AddressWithinSection
)
3387 PMMPTE StartPte
, EndPte
;
3388 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3391 /* Get the loader entry */
3392 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
3393 if (!LdrEntry
) return NULL
;
3395 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3396 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
3398 /* Don't do anything, just return the base address */
3399 return LdrEntry
->DllBase
;
3402 /* Wait for active DPCs to finish before we page out the driver */
3403 KeFlushQueuedDpcs();
3405 /* Get the PTE range for the whole driver image */
3406 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
3407 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
3409 /* Enable paging for the PTE range */
3410 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
3411 MiSetPagingOfDriver(StartPte
, EndPte
);
3413 /* Return the base address */
3414 return LdrEntry
->DllBase
;
3422 MmResetDriverPaging(IN PVOID AddressWithinSection
)
3432 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
3434 PVOID ProcAddress
= NULL
;
3435 ANSI_STRING AnsiRoutineName
;
3437 PLIST_ENTRY NextEntry
;
3438 PLDR_DATA_TABLE_ENTRY LdrEntry
;
3439 BOOLEAN Found
= FALSE
;
3440 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
3441 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
3444 /* Convert routine to ansi name */
3445 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
3448 if (!NT_SUCCESS(Status
)) return NULL
;
3451 KeEnterCriticalRegion();
3452 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
3454 /* Loop the loaded module list */
3455 NextEntry
= PsLoadedModuleList
.Flink
;
3456 while (NextEntry
!= &PsLoadedModuleList
)
3459 LdrEntry
= CONTAINING_RECORD(NextEntry
,
3460 LDR_DATA_TABLE_ENTRY
,
3463 /* Check if it's the kernel or HAL */
3464 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
3470 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
3477 /* Check if we found a valid binary */
3480 /* Find the procedure name */
3481 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
3484 /* Break out if we found it or if we already tried both modules */
3485 if (ProcAddress
) break;
3486 if (Modules
== 2) break;
3490 NextEntry
= NextEntry
->Flink
;
3493 /* Release the lock */
3494 ExReleaseResourceLite(&PsLoadedModuleResource
);
3495 KeLeaveCriticalRegion();
3497 /* Free the string and return */
3498 RtlFreeAnsiString(&AnsiRoutineName
);