2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/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 #line 16 "ARM³::LOADER"
17 #define MODULE_INVOLVED_IN_ARM3
18 #include "./ARM3/miarm.h"
20 /* GCC's incompetence strikes again */
23 sprintf_nt(IN PCHAR Buffer
,
29 vsprintf(Buffer
, Format
, ap
);
33 /* GLOBALS ********************************************************************/
35 LIST_ENTRY PsLoadedModuleList
;
36 LIST_ENTRY MmLoadedUserImageList
;
37 KSPIN_LOCK PsLoadedModuleSpinLock
;
38 ERESOURCE PsLoadedModuleResource
;
39 ULONG_PTR PsNtosImageBase
;
40 KMUTANT MmSystemLoadLock
;
42 PFN_NUMBER MmTotalSystemDriverPages
;
44 PVOID MmUnloadedDrivers
;
45 PVOID MmLastUnloadedDrivers
;
47 BOOLEAN MmMakeLowMemory
;
48 BOOLEAN MmEnforceWriteProtection
= TRUE
;
50 /* FUNCTIONS ******************************************************************/
54 MiCacheImageSymbols(IN PVOID BaseAddress
)
57 PVOID DebugDirectory
= NULL
;
60 /* Make sure it's safe to access the image */
63 /* Get the debug directory */
64 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
66 IMAGE_DIRECTORY_ENTRY_DEBUG
,
69 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
75 /* Return the directory */
76 return DebugDirectory
;
81 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
83 IN PUNICODE_STRING FileName
,
84 IN BOOLEAN SessionLoad
,
85 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
87 PROS_SECTION_OBJECT Section
= *SectionPtr
;
93 LARGE_INTEGER SectionOffset
= {{0, 0}};
94 BOOLEAN LoadSymbols
= FALSE
;
96 PMMPTE PointerPte
, LastPte
;
101 /* Detect session load */
105 DPRINT1("Session loading not yet supported!\n");
109 /* Not session load, shouldn't have an entry */
110 ASSERT(LdrEntry
== NULL
);
112 /* Attach to the system process */
113 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
115 /* Check if we need to load symbols */
116 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
120 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
124 Process
= PsGetCurrentProcess();
125 Status
= MmMapViewOfSection(Section
,
136 /* Re-enable the flag */
137 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
139 /* Check if we failed with distinguished status code */
140 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
142 /* Change it to something more generic */
143 Status
= STATUS_INVALID_IMAGE_FORMAT
;
146 /* Now check if we failed */
147 if (!NT_SUCCESS(Status
))
149 /* Detach and return */
150 KeUnstackDetachProcess(&ApcState
);
154 /* Reserve system PTEs needed */
155 PteCount
= ROUND_TO_PAGES(Section
->ImageSection
->ImageSize
) >> PAGE_SHIFT
;
156 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
157 if (!PointerPte
) return STATUS_INSUFFICIENT_RESOURCES
;
159 /* New driver base */
160 LastPte
= PointerPte
+ PteCount
;
161 DriverBase
= MiPteToAddress(PointerPte
);
163 /* The driver is here */
164 *ImageBase
= DriverBase
;
166 /* Loop the new driver PTEs */
167 TempPte
= ValidKernelPte
;
168 while (PointerPte
< LastPte
)
170 /* Allocate a page */
171 TempPte
.u
.Hard
.PageFrameNumber
= MmAllocPage(MC_NPPOOL
);
174 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
175 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
176 *PointerPte
= TempPte
;
183 RtlCopyMemory(DriverBase
, Base
, PteCount
<< PAGE_SHIFT
);
185 /* Now unmap the view */
186 Status
= MmUnmapViewOfSection(Process
, Base
);
187 ASSERT(NT_SUCCESS(Status
));
189 /* Detach and return status */
190 KeUnstackDetachProcess(&ApcState
);
196 MiLocateExportName(IN PVOID DllBase
,
200 PUSHORT OrdinalTable
;
201 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
202 LONG Low
= 0, Mid
= 0, High
, Ret
;
209 /* Get the export directory */
210 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
212 IMAGE_DIRECTORY_ENTRY_EXPORT
,
214 if (!ExportDirectory
) return NULL
;
216 /* Setup name tables */
217 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
218 ExportDirectory
->AddressOfNames
);
219 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
220 ExportDirectory
->AddressOfNameOrdinals
);
222 /* Do a binary search */
223 High
= ExportDirectory
->NumberOfNames
- 1;
226 /* Get new middle value */
227 Mid
= (Low
+ High
) >> 1;
230 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
248 /* Check if we couldn't find it */
249 if (High
< Low
) return NULL
;
251 /* Otherwise, this is the ordinal */
252 Ordinal
= OrdinalTable
[Mid
];
254 /* Resolve the address and write it */
255 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
256 ExportDirectory
->AddressOfFunctions
);
257 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
259 /* Check if the function is actually a forwarder */
260 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
261 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
273 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
274 IN PLIST_ENTRY ListHead
)
276 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(
277 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
278 PMM_DLL_INITIALIZE DllInit
;
279 UNICODE_STRING RegPath
, ImportName
;
282 /* Try to see if the image exports a DllInitialize routine */
283 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
285 if (!DllInit
) return STATUS_SUCCESS
;
287 /* Do a temporary copy of BaseDllName called ImportName
288 * because we'll alter the length of the string
290 ImportName
.Length
= LdrEntry
->BaseDllName
.Length
;
291 ImportName
.MaximumLength
= LdrEntry
->BaseDllName
.MaximumLength
;
292 ImportName
.Buffer
= LdrEntry
->BaseDllName
.Buffer
;
294 /* Obtain the path to this dll's service in the registry */
295 RegPath
.MaximumLength
= ServicesKeyName
.Length
+
296 ImportName
.Length
+ sizeof(UNICODE_NULL
);
297 RegPath
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
298 RegPath
.MaximumLength
,
301 /* Check if this allocation was unsuccessful */
302 if (!RegPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
304 /* Build and append the service name itself */
305 RegPath
.Length
= ServicesKeyName
.Length
;
306 RtlCopyMemory(RegPath
.Buffer
,
307 ServicesKeyName
.Buffer
,
308 ServicesKeyName
.Length
);
310 /* Check if there is a dot in the filename */
311 if (wcschr(ImportName
.Buffer
, L
'.'))
313 /* Remove the extension */
314 ImportName
.Length
= (wcschr(ImportName
.Buffer
, L
'.') -
315 ImportName
.Buffer
) * sizeof(WCHAR
);
318 /* Append service name (the basename without extension) */
319 RtlAppendUnicodeStringToString(&RegPath
, &ImportName
);
321 /* Now call the DllInit func */
322 DPRINT("Calling DllInit(%wZ)\n", &RegPath
);
323 Status
= DllInit(&RegPath
);
326 ExFreePool(RegPath
.Buffer
);
328 /* Return status value which DllInitialize returned */
334 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
340 /* Get the unload routine */
341 Func
= (PMM_DLL_UNLOAD
)MiLocateExportName(LdrEntry
->DllBase
, "DllUnload");
342 if (!Func
) return FALSE
;
344 /* Call it and check for success */
346 if (!NT_SUCCESS(Status
)) return FALSE
;
348 /* Lie about the load count so we can unload the image */
349 ASSERT(LdrEntry
->LoadCount
== 0);
350 LdrEntry
->LoadCount
= 1;
352 /* Unload it and return true */
353 MmUnloadSystemImage(LdrEntry
);
359 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
362 LOAD_IMPORTS SingleEntry
;
363 PLDR_DATA_TABLE_ENTRY LdrEntry
;
364 PVOID CurrentImports
;
367 /* Check if there's no imports or if we're a boot driver */
368 if ((ImportList
== MM_SYSLDR_NO_IMPORTS
) ||
369 (ImportList
== MM_SYSLDR_BOOT_LOADED
) ||
370 (ImportList
->Count
== 0))
372 /* Then there's nothing to do */
373 return STATUS_SUCCESS
;
376 /* Check for single-entry */
377 if ((ULONG_PTR
)ImportList
& MM_SYSLDR_SINGLE_ENTRY
)
380 SingleEntry
.Count
= 1;
381 SingleEntry
.Entry
[0] = (PVOID
)((ULONG_PTR
)ImportList
&~ MM_SYSLDR_SINGLE_ENTRY
);
383 /* Use this as the import list */
384 ImportList
= &SingleEntry
;
387 /* Loop the import list */
388 for (i
= 0; (i
< ImportList
->Count
) && (ImportList
->Entry
[i
]); i
++)
391 LdrEntry
= ImportList
->Entry
[i
];
392 DPRINT1("%wZ <%wZ>\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
394 /* Skip boot loaded images */
395 if (LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) continue;
397 /* Dereference the entry */
398 ASSERT(LdrEntry
->LoadCount
>= 1);
399 if (!--LdrEntry
->LoadCount
)
401 /* Save the import data in case unload fails */
402 CurrentImports
= LdrEntry
->LoadedImports
;
404 /* This is the last entry */
405 LdrEntry
->LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
406 if (MiCallDllUnloadAndUnloadDll(LdrEntry
))
408 /* Unloading worked, parse this DLL's imports too */
409 MiDereferenceImports(CurrentImports
);
411 /* Check if we had valid imports */
412 if ((CurrentImports
!= MM_SYSLDR_BOOT_LOADED
) ||
413 (CurrentImports
!= MM_SYSLDR_NO_IMPORTS
) ||
414 !((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
417 ExFreePool(CurrentImports
);
422 /* Unload failed, restore imports */
423 LdrEntry
->LoadedImports
= CurrentImports
;
429 return STATUS_SUCCESS
;
434 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
438 /* Check if there's no imports or we're a boot driver or only one entry */
439 if ((LdrEntry
->LoadedImports
== MM_SYSLDR_BOOT_LOADED
) ||
440 (LdrEntry
->LoadedImports
== MM_SYSLDR_NO_IMPORTS
) ||
441 ((ULONG_PTR
)LdrEntry
->LoadedImports
& MM_SYSLDR_SINGLE_ENTRY
))
447 /* Otherwise, free the import list */
448 ExFreePool(LdrEntry
->LoadedImports
);
449 LdrEntry
->LoadedImports
= MM_SYSLDR_BOOT_LOADED
;
454 MiFindExportedRoutineByName(IN PVOID DllBase
,
455 IN PANSI_STRING ExportName
)
458 PUSHORT OrdinalTable
;
459 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
460 LONG Low
= 0, Mid
= 0, High
, Ret
;
467 /* Get the export directory */
468 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
470 IMAGE_DIRECTORY_ENTRY_EXPORT
,
472 if (!ExportDirectory
) return NULL
;
474 /* Setup name tables */
475 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
476 ExportDirectory
->AddressOfNames
);
477 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
478 ExportDirectory
->AddressOfNameOrdinals
);
480 /* Do a binary search */
481 High
= ExportDirectory
->NumberOfNames
- 1;
484 /* Get new middle value */
485 Mid
= (Low
+ High
) >> 1;
488 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
506 /* Check if we couldn't find it */
507 if (High
< Low
) return NULL
;
509 /* Otherwise, this is the ordinal */
510 Ordinal
= OrdinalTable
[Mid
];
512 /* Resolve the address and write it */
513 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
514 ExportDirectory
->AddressOfFunctions
);
515 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
518 ASSERT(!(Function
> (PVOID
)ExportDirectory
) &&
519 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
525 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
530 /* Acquire module list lock */
531 KeEnterCriticalRegion();
532 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource
, TRUE
);
534 /* Acquire the spinlock too as we will insert or remove the entry */
535 OldIrql
= KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock
);
537 /* Insert or remove from the list */
538 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
539 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
542 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
543 ExReleaseResourceLite(&PsLoadedModuleResource
);
544 KeLeaveCriticalRegion();
549 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
554 ULONG_PTR OldBaseTop
, Delta
;
555 PLDR_DATA_TABLE_ENTRY LdrEntry
;
556 PLIST_ENTRY NextEntry
;
558 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
561 /* Calculate the top and delta */
562 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
563 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
565 /* Loop the loader block */
566 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
567 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
568 NextEntry
= NextEntry
->Flink
)
570 /* Get the loader entry */
571 LdrEntry
= CONTAINING_RECORD(NextEntry
,
572 LDR_DATA_TABLE_ENTRY
,
575 /* Get the import table */
576 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
578 IMAGE_DIRECTORY_ENTRY_IMPORT
,
580 if (!ImportDescriptor
) continue;
582 /* Make sure we have an IAT */
583 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
584 while ((ImportDescriptor
->Name
) &&
585 (ImportDescriptor
->OriginalFirstThunk
))
587 /* Get the image thunk */
588 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
589 ImportDescriptor
->FirstThunk
);
592 /* Check if it's within this module */
593 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
596 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
597 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
598 *ImageThunk
+= Delta
;
601 /* Go to the next thunk */
605 /* Go to the next import */
613 MiSnapThunk(IN PVOID DllBase
,
615 IN PIMAGE_THUNK_DATA Name
,
616 IN PIMAGE_THUNK_DATA Address
,
617 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
619 IN BOOLEAN SnapForwarder
,
620 OUT PCHAR
*MissingApi
)
625 PUSHORT OrdinalTable
;
626 PIMAGE_IMPORT_BY_NAME NameImport
;
628 ULONG Low
= 0, Mid
= 0, High
;
631 PCHAR MissingForwarder
;
632 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
635 UNICODE_STRING ForwarderName
;
636 PLIST_ENTRY NextEntry
;
637 PLDR_DATA_TABLE_ENTRY LdrEntry
;
638 ULONG ForwardExportSize
;
639 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
640 PIMAGE_IMPORT_BY_NAME ForwardName
;
642 IMAGE_THUNK_DATA ForwardThunk
;
645 /* Check if this is an ordinal */
646 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
647 if ((IsOrdinal
) && !(SnapForwarder
))
649 /* Get the ordinal number and set it as missing */
650 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
651 ExportDirectory
->Base
);
652 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
656 /* Get the VA if we don't have to snap */
657 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
658 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
660 /* Copy the procedure name */
662 (PCHAR
)&NameImport
->Name
[0],
663 MAXIMUM_FILENAME_LENGTH
- 1);
665 /* Setup name tables */
666 DPRINT("Import name: %s\n", NameImport
->Name
);
667 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
668 ExportDirectory
->AddressOfNames
);
669 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
670 ExportDirectory
->AddressOfNameOrdinals
);
672 /* Get the hint and check if it's valid */
673 Hint
= NameImport
->Hint
;
674 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
675 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
677 /* We have a match, get the ordinal number from here */
678 Ordinal
= OrdinalTable
[Hint
];
682 /* Do a binary search */
683 High
= ExportDirectory
->NumberOfNames
- 1;
686 /* Get new middle value */
687 Mid
= (Low
+ High
) >> 1;
690 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
708 /* Check if we couldn't find it */
709 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
711 /* Otherwise, this is the ordinal */
712 Ordinal
= OrdinalTable
[Mid
];
716 /* Check if the ordinal is invalid */
717 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
720 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
724 /* In case the forwarder is missing */
725 MissingForwarder
= NameBuffer
;
727 /* Resolve the address and write it */
728 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
729 ExportDirectory
->AddressOfFunctions
);
730 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
732 /* Assume success from now on */
733 Status
= STATUS_SUCCESS
;
735 /* Check if the function is actually a forwarder */
736 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
737 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
739 /* Now assume failure in case the forwarder doesn't exist */
740 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
742 /* Build the forwarder name */
743 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
744 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
747 DllName
.MaximumLength
= DllName
.Length
;
750 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
754 /* We failed, just return an error */
758 /* Loop the module list */
759 NextEntry
= PsLoadedModuleList
.Flink
;
760 while (NextEntry
!= &PsLoadedModuleList
)
762 /* Get the loader entry */
763 LdrEntry
= CONTAINING_RECORD(NextEntry
,
764 LDR_DATA_TABLE_ENTRY
,
767 /* Check if it matches */
768 if (RtlPrefixString((PSTRING
)&ForwarderName
,
769 (PSTRING
)&LdrEntry
->BaseDllName
,
772 /* Get the forwarder export directory */
773 ForwardExportDirectory
=
774 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
776 IMAGE_DIRECTORY_ENTRY_EXPORT
,
778 if (!ForwardExportDirectory
) break;
780 /* Allocate a name entry */
781 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
783 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
784 sizeof(*ForwardName
) +
787 if (!ForwardName
) break;
790 RtlCopyMemory(&ForwardName
->Name
[0],
791 DllName
.Buffer
+ DllName
.Length
,
793 ForwardName
->Hint
= 0;
795 /* Set the new address */
796 ForwardThunk
.u1
.AddressOfData
= (ULONG_PTR
)ForwardName
;
798 /* Snap the forwarder */
799 Status
= MiSnapThunk(LdrEntry
->DllBase
,
803 ForwardExportDirectory
,
808 /* Free the forwarder name and set the thunk */
809 ExFreePoolWithTag(ForwardName
, TAG_LDR_WSTR
);
810 Address
->u1
= ForwardThunk
.u1
;
814 /* Go to the next entry */
815 NextEntry
= NextEntry
->Flink
;
819 RtlFreeUnicodeString(&ForwarderName
);
829 MmUnloadSystemImage(IN PVOID ImageHandle
)
831 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
832 PVOID BaseAddress
= LdrEntry
->DllBase
;
835 BOOLEAN HadEntry
= FALSE
;
837 /* Acquire the loader lock */
838 KeEnterCriticalRegion();
839 KeWaitForSingleObject(&MmSystemLoadLock
,
845 /* Check if this driver was loaded at boot and didn't get imports parsed */
846 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
848 /* We should still be alive */
849 ASSERT(LdrEntry
->LoadCount
!= 0);
850 LdrEntry
->LoadCount
--;
852 /* Check if we're still loaded */
853 if (LdrEntry
->LoadCount
) goto Done
;
855 /* We should cleanup... are symbols loaded */
856 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
858 /* Create the ANSI name */
859 Status
= RtlUnicodeStringToAnsiString(&TempName
,
860 &LdrEntry
->BaseDllName
,
862 if (NT_SUCCESS(Status
))
864 /* Unload the symbols */
865 DbgUnLoadImageSymbols(&TempName
,
867 (ULONG_PTR
)ZwCurrentProcess());
868 RtlFreeAnsiString(&TempName
);
872 /* FIXME: Free the driver */
873 //MmFreeSection(LdrEntry->DllBase);
875 /* Check if we're linked in */
876 if (LdrEntry
->InLoadOrderLinks
.Flink
)
879 MiProcessLoaderEntry(LdrEntry
, FALSE
);
883 /* Dereference and clear the imports */
884 MiDereferenceImports(LdrEntry
->LoadedImports
);
885 MiClearImports(LdrEntry
);
887 /* Check if the entry needs to go away */
890 /* Check if it had a name */
891 if (LdrEntry
->FullDllName
.Buffer
)
894 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
897 /* Check if we had a section */
898 if (LdrEntry
->SectionPointer
)
901 ObDereferenceObject(LdrEntry
->SectionPointer
);
905 ExFreePool(LdrEntry
);
908 /* Release the system lock and return */
910 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
911 KeLeaveCriticalRegion();
912 return STATUS_SUCCESS
;
917 MiResolveImageReferences(IN PVOID ImageBase
,
918 IN PUNICODE_STRING ImageFileDirectory
,
919 IN PUNICODE_STRING NamePrefix OPTIONAL
,
920 OUT PCHAR
*MissingApi
,
921 OUT PWCHAR
*MissingDriver
,
922 OUT PLOAD_IMPORTS
*LoadImports
)
924 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
925 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
926 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
927 PLOAD_IMPORTS LoadedImports
, NewImports
;
928 ULONG GdiLink
, NormalLink
, i
;
929 BOOLEAN ReferenceNeeded
, Loaded
;
930 ANSI_STRING TempString
;
931 UNICODE_STRING NameString
, DllName
;
932 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
933 PVOID ImportBase
, DllBase
;
934 PLIST_ENTRY NextEntry
;
935 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
937 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
939 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
940 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
942 /* Assume no imports */
943 *LoadImports
= (PVOID
)-2;
945 /* Get the import descriptor */
946 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
948 IMAGE_DIRECTORY_ENTRY_IMPORT
,
950 if (!ImportDescriptor
) return STATUS_SUCCESS
;
952 /* Loop all imports to count them */
953 for (CurrentImport
= ImportDescriptor
;
954 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
961 /* Make sure we have non-zero imports */
964 /* Calculate and allocate the list we'll need */
965 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
966 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
972 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
978 LoadedImports
= NULL
;
981 /* Reset the import count and loop descriptors again */
982 ImportCount
= GdiLink
= NormalLink
= 0;
983 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
986 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
988 /* Check if this is a GDI driver */
990 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
992 /* We can also allow dxapi */
993 NormalLink
= NormalLink
|
994 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
995 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
997 /* Check if this is a valid GDI driver */
998 if ((GdiLink
) && (NormalLink
))
1000 /* It's not, it's importing stuff it shouldn't be! */
1001 MiDereferenceImports(LoadedImports
);
1002 if (LoadedImports
) ExFreePool(LoadedImports
);
1003 return STATUS_PROCEDURE_NOT_FOUND
;
1006 /* Check if this is a "core" import, which doesn't get referenced */
1007 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1008 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
1009 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
1011 /* Don't reference this */
1012 ReferenceNeeded
= FALSE
;
1016 /* Reference these modules */
1017 ReferenceNeeded
= TRUE
;
1020 /* Now setup a unicode string for the import */
1021 RtlInitAnsiString(&TempString
, ImportName
);
1022 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
1023 if (!NT_SUCCESS(Status
))
1026 MiDereferenceImports(LoadedImports
);
1027 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1031 /* We don't support name prefixes yet */
1032 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
1034 /* Remember that we haven't loaded the import at this point */
1039 /* Loop the driver list */
1040 NextEntry
= PsLoadedModuleList
.Flink
;
1041 while (NextEntry
!= &PsLoadedModuleList
)
1043 /* Get the loader entry and compare the name */
1044 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1045 LDR_DATA_TABLE_ENTRY
,
1047 if (RtlEqualUnicodeString(&NameString
,
1048 &LdrEntry
->BaseDllName
,
1051 /* Get the base address */
1052 ImportBase
= LdrEntry
->DllBase
;
1054 /* Check if we haven't loaded yet, and we need references */
1055 if (!(Loaded
) && (ReferenceNeeded
))
1057 /* Make sure we're not already loading */
1058 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1060 /* Increase the load count */
1061 LdrEntry
->LoadCount
++;
1065 /* Done, break out */
1069 /* Go to the next entry */
1070 NextEntry
= NextEntry
->Flink
;
1073 /* Check if we haven't loaded the import yet */
1076 /* Setup the import DLL name */
1077 DllName
.MaximumLength
= NameString
.Length
+
1078 ImageFileDirectory
->Length
+
1079 sizeof(UNICODE_NULL
);
1080 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1081 DllName
.MaximumLength
,
1085 /* Setup the base length and copy it */
1086 DllName
.Length
= ImageFileDirectory
->Length
;
1087 RtlCopyMemory(DllName
.Buffer
,
1088 ImageFileDirectory
->Buffer
,
1089 ImageFileDirectory
->Length
);
1091 /* Now add the import name and null-terminate it */
1092 RtlAppendStringToString((PSTRING
)&DllName
,
1093 (PSTRING
)&NameString
);
1094 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / sizeof(WCHAR
)] = UNICODE_NULL
;
1096 /* Load the image */
1097 Status
= MmLoadSystemImage(&DllName
,
1103 if (NT_SUCCESS(Status
))
1105 /* We can free the DLL Name */
1106 ExFreePool(DllName
.Buffer
);
1110 /* Fill out the information for the error */
1111 *MissingDriver
= DllName
.Buffer
;
1112 *(PULONG
)MissingDriver
|= 1;
1118 /* We're out of resources */
1119 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1122 /* Check if we're OK until now */
1123 if (NT_SUCCESS(Status
))
1125 /* We're now loaded */
1129 ASSERT(DllBase
= DllEntry
->DllBase
);
1131 /* Call the initialization routines */
1132 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
1133 if (!NT_SUCCESS(Status
))
1135 /* We failed, unload the image */
1136 MmUnloadSystemImage(DllEntry
);
1142 /* Check if we failed by here */
1143 if (!NT_SUCCESS(Status
))
1145 /* Cleanup and return */
1146 RtlFreeUnicodeString(&NameString
);
1147 MiDereferenceImports(LoadedImports
);
1148 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1152 /* Loop again to make sure that everything is OK */
1156 /* Check if we're support to reference this import */
1157 if ((ReferenceNeeded
) && (LoadedImports
))
1159 /* Make sure we're not already loading */
1160 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1163 LoadedImports
->Entry
[LoadedImports
->Count
] = LdrEntry
;
1164 LoadedImports
->Count
++;
1168 /* Free the import name */
1169 RtlFreeUnicodeString(&NameString
);
1171 /* Set the missing driver name and get the export directory */
1172 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1173 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1175 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1177 if (!ExportDirectory
)
1179 /* Cleanup and return */
1180 MiDereferenceImports(LoadedImports
);
1181 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1182 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1185 /* Make sure we have an IAT */
1186 if (ImportDescriptor
->OriginalFirstThunk
)
1188 /* Get the first thunks */
1189 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1190 ImportDescriptor
->OriginalFirstThunk
);
1191 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1192 ImportDescriptor
->FirstThunk
);
1195 while (OrigThunk
->u1
.AddressOfData
)
1198 Status
= MiSnapThunk(ImportBase
,
1206 if (!NT_SUCCESS(Status
))
1208 /* Cleanup and return */
1209 MiDereferenceImports(LoadedImports
);
1210 if (LoadedImports
) ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1214 /* Reset the buffer */
1215 *MissingApi
= MissingApiBuffer
;
1219 /* Go to the next import */
1223 /* Check if we have an import list */
1226 /* Reset the count again, and loop entries*/
1228 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1230 if (LoadedImports
->Entry
[i
])
1232 /* Got an entry, OR it with 1 in case it's the single entry */
1233 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1238 /* Check if we had no imports */
1241 /* Free the list and set it to no imports */
1242 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1243 LoadedImports
= (PVOID
)-2;
1245 else if (ImportCount
== 1)
1247 /* Just one entry, we can free the table and only use our entry */
1248 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1249 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1251 else if (ImportCount
!= LoadedImports
->Count
)
1253 /* Allocate a new list */
1254 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1255 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1261 NewImports
->Count
= 0;
1263 /* Loop all the imports */
1264 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1266 /* Make sure it's valid */
1267 if (LoadedImports
->Entry
[i
])
1270 NewImports
->Entry
[NewImports
->Count
] = LoadedImports
->Entry
[i
];
1271 NewImports
->Count
++;
1275 /* Free the old copy */
1276 ExFreePoolWithTag(LoadedImports
, TAG_LDR_WSTR
);
1277 LoadedImports
= NewImports
;
1281 /* Return the list */
1282 *LoadImports
= LoadedImports
;
1285 /* Return success */
1286 return STATUS_SUCCESS
;
1291 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1293 PLIST_ENTRY NextEntry
;
1295 PIMAGE_NT_HEADERS NtHeader
;
1296 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1297 PIMAGE_FILE_HEADER FileHeader
;
1298 BOOLEAN ValidRelocs
;
1299 PIMAGE_DATA_DIRECTORY DataDirectory
;
1300 PVOID DllBase
, NewImageAddress
;
1302 PMMPTE PointerPte
, StartPte
, LastPte
;
1303 PFN_NUMBER PteCount
;
1305 MMPTE TempPte
, OldPte
;
1307 /* Loop driver list */
1308 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1309 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1310 NextEntry
= NextEntry
->Flink
)
1312 /* Get the loader entry and NT header */
1313 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1314 LDR_DATA_TABLE_ENTRY
,
1316 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1319 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1321 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1322 &LdrEntry
->FullDllName
);
1324 /* Skip kernel and HAL */
1325 /* ROS HACK: Skip BOOTVID/KDCOM too */
1327 if (i
<= 4) continue;
1329 /* Skip non-drivers */
1330 if (!NtHeader
) continue;
1332 /* Get the file header and make sure we can relocate */
1333 FileHeader
= &NtHeader
->FileHeader
;
1334 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1335 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1336 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1338 /* Everything made sense until now, check the relocation section too */
1339 DataDirectory
= &NtHeader
->OptionalHeader
.
1340 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1341 if (!DataDirectory
->VirtualAddress
)
1343 /* We don't really have relocations */
1344 ValidRelocs
= FALSE
;
1348 /* Make sure the size is valid */
1349 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1350 LdrEntry
->SizeOfImage
)
1352 /* They're not, skip */
1356 /* We have relocations */
1360 /* Remember the original address */
1361 DllBase
= LdrEntry
->DllBase
;
1363 /* Get the first PTE and the number of PTEs we'll need */
1364 PointerPte
= StartPte
= MiAddressToPte(LdrEntry
->DllBase
);
1365 PteCount
= ROUND_TO_PAGES(LdrEntry
->SizeOfImage
) >> PAGE_SHIFT
;
1366 LastPte
= StartPte
+ PteCount
;
1369 while (PointerPte
< LastPte
)
1371 /* Mark the page modified in the PFN database */
1372 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1373 Pfn1
= MiGetPfnEntry(PFN_FROM_PTE(PointerPte
));
1374 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1375 Pfn1
->u3
.e1
.Modified
= TRUE
;
1381 /* Now reserve system PTEs for the image */
1382 PointerPte
= MiReserveSystemPtes(PteCount
, SystemPteSpace
);
1385 /* Shouldn't happen */
1386 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1390 /* This is the new virtual address for the module */
1391 LastPte
= PointerPte
+ PteCount
;
1392 NewImageAddress
= MiPteToAddress(PointerPte
);
1395 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1396 ASSERT(ExpInitializationPhase
== 0);
1398 /* Loop the new driver PTEs */
1399 TempPte
= ValidKernelPte
;
1400 while (PointerPte
< LastPte
)
1402 /* Copy the old data */
1404 ASSERT(OldPte
.u
.Hard
.Valid
== 1);
1406 /* Set page number from the loader's memory */
1407 TempPte
.u
.Hard
.PageFrameNumber
= OldPte
.u
.Hard
.PageFrameNumber
;
1410 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1411 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
1412 *PointerPte
= TempPte
;
1419 /* Update position */
1420 PointerPte
-= PteCount
;
1423 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1425 /* Set the image base to the address where the loader put it */
1426 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1428 /* Check if we had relocations */
1431 /* Relocate the image */
1432 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1436 STATUS_CONFLICTING_ADDRESSES
,
1437 STATUS_INVALID_IMAGE_FORMAT
);
1438 if (!NT_SUCCESS(Status
))
1440 /* This shouldn't happen */
1441 DPRINT1("Relocations failed!\n");
1446 /* Update the loader entry */
1447 LdrEntry
->DllBase
= NewImageAddress
;
1449 /* Update the thunks */
1450 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1451 MiUpdateThunks(LoaderBlock
,
1454 LdrEntry
->SizeOfImage
);
1456 /* Update the loader entry */
1457 LdrEntry
->Flags
|= LDRP_SYSTEM_MAPPED
;
1458 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1459 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1460 LdrEntry
->SizeOfImage
= PteCount
<< PAGE_SHIFT
;
1462 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1468 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1470 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1471 PLIST_ENTRY ListHead
, NextEntry
;
1474 /* Setup the loaded module list and locks */
1475 ExInitializeResourceLite(&PsLoadedModuleResource
);
1476 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1477 InitializeListHead(&PsLoadedModuleList
);
1479 /* Get loop variables and the kernel entry */
1480 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1481 NextEntry
= ListHead
->Flink
;
1482 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1483 LDR_DATA_TABLE_ENTRY
,
1485 PsNtosImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1487 /* Loop the loader block */
1488 while (NextEntry
!= ListHead
)
1490 /* Get the loader entry */
1491 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1492 LDR_DATA_TABLE_ENTRY
,
1495 /* FIXME: ROS HACK. Make sure this is a driver */
1496 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1498 /* Skip this entry */
1499 NextEntry
= NextEntry
->Flink
;
1503 /* Calculate the size we'll need and allocate a copy */
1504 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1505 LdrEntry
->BaseDllName
.MaximumLength
+
1506 sizeof(UNICODE_NULL
);
1507 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1508 if (!NewEntry
) return FALSE
;
1510 /* Copy the entry over */
1511 *NewEntry
= *LdrEntry
;
1513 /* Allocate the name */
1514 NewEntry
->FullDllName
.Buffer
=
1515 ExAllocatePoolWithTag(PagedPool
,
1516 LdrEntry
->FullDllName
.MaximumLength
+
1517 sizeof(UNICODE_NULL
),
1519 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1521 /* Set the base name */
1522 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1524 /* Copy the full and base name */
1525 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1526 LdrEntry
->FullDllName
.Buffer
,
1527 LdrEntry
->FullDllName
.MaximumLength
);
1528 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1529 LdrEntry
->BaseDllName
.Buffer
,
1530 LdrEntry
->BaseDllName
.MaximumLength
);
1532 /* Null-terminate the base name */
1533 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1534 sizeof(WCHAR
)] = UNICODE_NULL
;
1536 /* Insert the entry into the list */
1537 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1538 NextEntry
= NextEntry
->Flink
;
1541 /* Build the import lists for the boot drivers */
1542 //MiBuildImportsForBootDrivers();
1550 MiComputeDriverProtection(IN BOOLEAN SessionSpace
,
1551 IN ULONG SectionProtection
)
1553 ULONG Protection
= MM_ZERO_ACCESS
;
1555 /* Check if the caller gave anything */
1556 if (SectionProtection
)
1558 /* Always turn on execute access */
1559 SectionProtection
|= IMAGE_SCN_MEM_EXECUTE
;
1561 /* Check if the registry setting is on or not */
1562 if (!MmEnforceWriteProtection
)
1564 /* Turn on write access too */
1565 SectionProtection
|= (IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_EXECUTE
);
1569 /* Convert to internal PTE flags */
1570 if (SectionProtection
& IMAGE_SCN_MEM_EXECUTE
) Protection
|= MM_EXECUTE
;
1571 if (SectionProtection
& IMAGE_SCN_MEM_READ
) Protection
|= MM_READONLY
;
1573 /* Check for write access */
1574 if (SectionProtection
& IMAGE_SCN_MEM_WRITE
)
1576 /* Session space is not supported */
1579 DPRINT1("Session drivers not supported\n");
1580 ASSERT(SessionSpace
== FALSE
);
1584 /* Convert to internal PTE flag */
1585 Protection
= (Protection
& MM_EXECUTE
) ? MM_EXECUTE_READWRITE
: MM_READWRITE
;
1589 /* If there's no access at all by now, convert to internal no access flag */
1590 if (Protection
== MM_ZERO_ACCESS
) Protection
= MM_NOACCESS
;
1592 /* Return the computed PTE protection */
1598 MiSetSystemCodeProtection(IN PMMPTE FirstPte
,
1600 IN ULONG ProtectionMask
)
1602 /* I'm afraid to introduce regressions at the moment... */
1608 MiWriteProtectSystemImage(IN PVOID ImageBase
)
1610 PIMAGE_NT_HEADERS NtHeaders
;
1611 PIMAGE_SECTION_HEADER Section
;
1612 PFN_NUMBER DriverPages
;
1613 ULONG CurrentProtection
, SectionProtection
, CombinedProtection
, ProtectionMask
;
1614 ULONG Sections
, Size
;
1615 ULONG_PTR BaseAddress
, CurrentAddress
;
1616 PMMPTE PointerPte
, StartPte
, LastPte
, CurrentPte
, ComboPte
= NULL
;
1617 ULONG CurrentMask
, CombinedMask
= 0;
1620 /* No need to write protect physical memory-backed drivers (large pages) */
1621 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
1623 /* Get the image headers */
1624 NtHeaders
= RtlImageNtHeader(ImageBase
);
1625 if (!NtHeaders
) return;
1627 /* Check if this is a session driver or not */
1628 if (!MI_IS_SESSION_ADDRESS(ImageBase
))
1630 /* Don't touch NT4 drivers */
1631 if (NtHeaders
->OptionalHeader
.MajorOperatingSystemVersion
< 5) return;
1632 if (NtHeaders
->OptionalHeader
.MajorImageVersion
< 5) return;
1637 DPRINT1("Session drivers not supported\n");
1641 /* These are the only protection masks we care about */
1642 ProtectionMask
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_EXECUTE
;
1644 /* Calculate the number of pages this driver is occupying */
1645 DriverPages
= BYTES_TO_PAGES(NtHeaders
->OptionalHeader
.SizeOfImage
);
1647 /* Get the number of sections and the first section header */
1648 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1649 ASSERT(Sections
!= 0);
1650 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
1652 /* Loop all the sections */
1653 CurrentAddress
= (ULONG_PTR
)ImageBase
;
1656 /* Get the section size */
1657 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1659 /* Get its virtual address */
1660 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
1661 if (BaseAddress
< CurrentAddress
)
1663 /* Windows doesn't like these */
1664 DPRINT1("Badly linked image!\n");
1668 /* Remember the current address */
1669 CurrentAddress
= BaseAddress
+ Size
- 1;
1676 /* Get the number of sections and the first section header */
1677 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1678 ASSERT(Sections
!= 0);
1679 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
1681 /* Set the address at the end to initialize the loop */
1682 CurrentAddress
= (ULONG_PTR
)Section
+ Sections
- 1;
1683 CurrentProtection
= IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
;
1685 /* Set the PTE points for the image, and loop its sections */
1686 StartPte
= MiAddressToPte(ImageBase
);
1687 LastPte
= StartPte
+ DriverPages
;
1690 /* Get the section size */
1691 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1693 /* Get its virtual address and PTE */
1694 BaseAddress
= (ULONG_PTR
)ImageBase
+ Section
->VirtualAddress
;
1695 PointerPte
= MiAddressToPte(BaseAddress
);
1697 /* Check if we were already protecting a run, and found a new run */
1698 if ((ComboPte
) && (PointerPte
> ComboPte
))
1700 /* Compute protection */
1701 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
1704 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
1706 /* Check for overlap */
1707 if (ComboPte
== StartPte
) StartPte
++;
1709 /* One done, reset variables */
1711 CombinedProtection
= 0;
1714 /* Break out when needed */
1715 if (PointerPte
>= LastPte
) break;
1717 /* Get the requested protection from the image header */
1718 SectionProtection
= Section
->Characteristics
& ProtectionMask
;
1719 if (SectionProtection
== CurrentProtection
)
1721 /* Same protection, so merge the request */
1722 CurrentAddress
= BaseAddress
+ Size
- 1;
1726 /* This is now a new section, so close up the old one */
1727 CurrentPte
= MiAddressToPte(CurrentAddress
);
1729 /* Check for overlap */
1730 if (CurrentPte
== PointerPte
)
1732 /* Skip the last PTE, since it overlaps with us */
1735 /* And set the PTE we will merge with */
1736 ASSERT((ComboPte
== NULL
) || (ComboPte
== PointerPte
));
1737 ComboPte
= PointerPte
;
1739 /* Get the most flexible protection by merging both */
1740 CombinedMask
|= (SectionProtection
| CurrentProtection
);
1743 /* Loop any PTEs left */
1744 if (CurrentPte
>= StartPte
)
1747 ASSERT(StartPte
< LastPte
);
1749 /* Make sure we don't overflow past the last PTE in the driver */
1750 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
1751 ASSERT(CurrentPte
>= StartPte
);
1753 /* Compute the protection and set it */
1754 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
1755 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
1759 StartPte
= PointerPte
;
1760 CurrentAddress
= BaseAddress
+ Size
- 1;
1761 CurrentProtection
= SectionProtection
;
1768 /* Is there a leftover section to merge? */
1771 /* Compute and set the protection */
1772 CombinedMask
= MiComputeDriverProtection(FALSE
, CombinedProtection
);
1773 MiSetSystemCodeProtection(ComboPte
, ComboPte
, CombinedMask
);
1775 /* Handle overlap */
1776 if (ComboPte
== StartPte
) StartPte
++;
1779 /* Finally, handle the last section */
1780 CurrentPte
= MiPteToAddress(CurrentAddress
);
1781 if ((StartPte
< LastPte
) && (CurrentPte
>= StartPte
))
1783 /* Handle overlap */
1784 if (CurrentPte
>= LastPte
) CurrentPte
= LastPte
- 1;
1785 ASSERT(CurrentPte
>= StartPte
);
1787 /* Compute and set the protection */
1788 CurrentMask
= MiComputeDriverProtection(FALSE
, CurrentProtection
);
1789 MiSetSystemCodeProtection(StartPte
, CurrentPte
, CurrentMask
);
1795 MiSetPagingOfDriver(IN PMMPTE PointerPte
,
1799 PETHREAD CurrentThread
;
1800 PFN_NUMBER PageCount
= 0, PageFrameIndex
;
1804 /* Get the driver's base address */
1805 ImageBase
= MiPteToAddress(PointerPte
);
1806 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase
) == FALSE
);
1808 /* If this is a large page, it's stuck in physical memory */
1809 if (MI_IS_PHYSICAL_ADDRESS(ImageBase
)) return;
1811 /* We should lock the system working set -- we don't have one yet, so just be consistent */
1812 CurrentThread
= PsGetCurrentThread();
1813 KeEnterGuardedRegion();
1814 ASSERT((CurrentThread
->OwnsSystemWorkingSetExclusive
== 0) &&
1815 (CurrentThread
->OwnsSystemWorkingSetShared
== 0));
1816 CurrentThread
->OwnsSystemWorkingSetExclusive
= 1;
1819 while (PointerPte
<= LastPte
)
1821 /* Check for valid PTE */
1822 if (PointerPte
->u
.Hard
.Valid
== 1)
1824 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
1825 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
1826 ASSERT(Pfn1
->u2
.ShareCount
== 1);
1828 /* No working sets in ReactOS yet */
1832 ImageBase
= (PVOID
)((ULONG_PTR
)ImageBase
+ PAGE_SIZE
);
1836 /* Release the working set "lock" */
1837 ASSERT(KeAreAllApcsDisabled() == TRUE
);
1838 CurrentThread
->OwnsSystemWorkingSetExclusive
= 0;
1839 KeLeaveGuardedRegion();
1841 /* Do we have any driver pages? */
1844 /* Update counters */
1845 InterlockedExchangeAdd((PLONG
)&MmTotalSystemDriverPages
, PageCount
);
1851 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
1853 ULONG_PTR ImageBase
;
1854 PIMAGE_NT_HEADERS NtHeaders
;
1855 ULONG Sections
, Alignment
, Size
;
1856 PIMAGE_SECTION_HEADER Section
;
1857 PMMPTE PointerPte
= NULL
, LastPte
= NULL
;
1858 if (MmDisablePagingExecutive
) return;
1860 /* Get the driver base address and its NT header */
1861 ImageBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
1862 NtHeaders
= RtlImageNtHeader((PVOID
)ImageBase
);
1863 if (!NtHeaders
) return;
1865 /* Get the sections and their alignment */
1866 Sections
= NtHeaders
->FileHeader
.NumberOfSections
;
1867 Alignment
= NtHeaders
->OptionalHeader
.SectionAlignment
- 1;
1869 /* Loop each section */
1870 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
1873 /* Find PAGE or .edata */
1874 if ((*(PULONG
)Section
->Name
== 'EGAP') ||
1875 (*(PULONG
)Section
->Name
== 'ade.'))
1877 /* Had we already done some work? */
1880 /* Nope, setup the first PTE address */
1881 PointerPte
= MiAddressToPte(ROUND_TO_PAGES(ImageBase
+
1886 /* Compute the size */
1887 Size
= max(Section
->SizeOfRawData
, Section
->Misc
.VirtualSize
);
1889 /* Find the last PTE that maps this section */
1890 LastPte
= MiAddressToPte(ImageBase
+
1891 Section
->VirtualAddress
+
1898 /* Had we found a section before? */
1901 /* Mark it as pageable */
1902 MiSetPagingOfDriver(PointerPte
, LastPte
);
1907 /* Keep searching */
1912 /* Handle the straggler */
1913 if (PointerPte
) MiSetPagingOfDriver(PointerPte
, LastPte
);
1918 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1920 PIMAGE_NT_HEADERS NtHeader
;
1923 /* Get NT Headers */
1924 NtHeader
= RtlImageNtHeader(BaseAddress
);
1927 /* Check if this image is only safe for UP while we have 2+ CPUs */
1928 if ((KeNumberProcessors
> 1) &&
1929 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1936 /* Otherwise, it's safe */
1942 MmCheckSystemImage(IN HANDLE ImageHandle
,
1943 IN BOOLEAN PurgeSection
)
1946 HANDLE SectionHandle
;
1947 PVOID ViewBase
= NULL
;
1948 SIZE_T ViewSize
= 0;
1949 IO_STATUS_BLOCK IoStatusBlock
;
1950 FILE_STANDARD_INFORMATION FileStandardInfo
;
1951 KAPC_STATE ApcState
;
1954 /* Create a section for the DLL */
1955 Status
= ZwCreateSection(&SectionHandle
,
1956 SECTION_MAP_EXECUTE
,
1962 if (!NT_SUCCESS(Status
)) return Status
;
1964 /* Make sure we're in the system process */
1965 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1968 Status
= ZwMapViewOfSection(SectionHandle
,
1978 if (!NT_SUCCESS(Status
))
1980 /* We failed, close the handle and return */
1981 KeUnstackDetachProcess(&ApcState
);
1982 ZwClose(SectionHandle
);
1986 /* Now query image information */
1987 Status
= ZwQueryInformationFile(ImageHandle
,
1990 sizeof(FileStandardInfo
),
1991 FileStandardInformation
);
1992 if ( NT_SUCCESS(Status
) )
1994 /* First, verify the checksum */
1995 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
2001 /* Set checksum failure */
2002 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2005 /* Check that it's a valid SMP image if we have more then one CPU */
2006 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
2008 /* Otherwise it's not the right image */
2009 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
2013 /* Unmap the section, close the handle, and return status */
2014 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
2015 KeUnstackDetachProcess(&ApcState
);
2016 ZwClose(SectionHandle
);
2022 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
2023 IN PUNICODE_STRING NamePrefix OPTIONAL
,
2024 IN PUNICODE_STRING LoadedName OPTIONAL
,
2026 OUT PVOID
*ModuleObject
,
2027 OUT PVOID
*ImageBaseAddress
)
2029 PVOID ModuleLoadBase
= NULL
;
2031 HANDLE FileHandle
= NULL
;
2032 OBJECT_ATTRIBUTES ObjectAttributes
;
2033 IO_STATUS_BLOCK IoStatusBlock
;
2034 PIMAGE_NT_HEADERS NtHeader
;
2035 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
2036 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
2037 ULONG EntrySize
, DriverSize
;
2038 PLOAD_IMPORTS LoadedImports
= MM_SYSLDR_NO_IMPORTS
;
2039 PCHAR MissingApiName
, Buffer
;
2040 PWCHAR MissingDriverName
;
2041 HANDLE SectionHandle
;
2042 ACCESS_MASK DesiredAccess
;
2043 PVOID Section
= NULL
;
2044 BOOLEAN LockOwned
= FALSE
;
2045 PLIST_ENTRY NextEntry
;
2046 IMAGE_INFO ImageInfo
;
2050 /* Detect session-load */
2054 ASSERT(NamePrefix
== NULL
);
2055 ASSERT(LoadedName
== NULL
);
2057 /* Make sure the process is in session too */
2058 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
2061 /* Allocate a buffer we'll use for names */
2062 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, 'nLmM');
2063 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2065 /* Check for a separator */
2066 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
2071 /* Loop the path until we get to the base name */
2072 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
2073 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
2075 /* Get the length */
2076 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
2077 BaseLength
*= sizeof(WCHAR
);
2079 /* Setup the string */
2080 BaseName
.Length
= (USHORT
)BaseLength
;
2081 BaseName
.Buffer
= p
;
2085 /* Otherwise, we already have a base name */
2086 BaseName
.Length
= FileName
->Length
;
2087 BaseName
.Buffer
= FileName
->Buffer
;
2090 /* Setup the maximum length */
2091 BaseName
.MaximumLength
= BaseName
.Length
;
2093 /* Now compute the base directory */
2094 BaseDirectory
= *FileName
;
2095 BaseDirectory
.Length
-= BaseName
.Length
;
2096 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
2098 /* And the prefix, which for now is just the name itself */
2099 PrefixName
= *FileName
;
2101 /* Check if we have a prefix */
2102 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
2104 /* Check if we already have a name, use it instead */
2105 if (LoadedName
) BaseName
= *LoadedName
;
2107 /* Check for loader snap debugging */
2108 if (NtGlobalFlag
& FLG_SHOW_LDR_SNAPS
)
2110 /* Print out standard string */
2111 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2112 &PrefixName
, &BaseName
, Flags
? "in session space" : "");
2115 /* Acquire the load lock */
2117 ASSERT(LockOwned
== FALSE
);
2119 KeEnterCriticalRegion();
2120 KeWaitForSingleObject(&MmSystemLoadLock
,
2126 /* Scan the module list */
2127 NextEntry
= PsLoadedModuleList
.Flink
;
2128 while (NextEntry
!= &PsLoadedModuleList
)
2130 /* Get the entry and compare the names */
2131 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2132 LDR_DATA_TABLE_ENTRY
,
2134 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
2136 /* Found it, break out */
2141 NextEntry
= NextEntry
->Flink
;
2144 /* Check if we found the image */
2145 if (NextEntry
!= &PsLoadedModuleList
)
2147 /* Check if we had already mapped a section */
2150 /* Dereference and clear */
2151 ObDereferenceObject(Section
);
2155 /* Check if this was supposed to be a session load */
2158 /* It wasn't, so just return the data */
2159 *ModuleObject
= LdrEntry
;
2160 *ImageBaseAddress
= LdrEntry
->DllBase
;
2161 Status
= STATUS_IMAGE_ALREADY_LOADED
;
2165 /* We don't support session loading yet */
2166 DPRINT1("Unsupported Session-Load!\n");
2175 /* It wasn't loaded, and we didn't have a previous attempt */
2176 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2177 KeLeaveCriticalRegion();
2180 /* Check if KD is enabled */
2181 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
2183 /* FIXME: Attempt to get image from KD */
2186 /* We don't have a valid entry */
2189 /* Setup image attributes */
2190 InitializeObjectAttributes(&ObjectAttributes
,
2192 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2196 /* Open the image */
2197 Status
= ZwOpenFile(&FileHandle
,
2201 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2203 if (!NT_SUCCESS(Status
)) goto Quickie
;
2206 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
2207 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
2208 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
2209 (Status
== STATUS_INVALID_IMAGE_PROTECT
))
2215 /* Check if this is a session-load */
2218 /* Then we only need read and execute */
2219 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
2223 /* Otherwise, we can allow write access */
2224 DesiredAccess
= SECTION_ALL_ACCESS
;
2227 /* Initialize the attributes for the section */
2228 InitializeObjectAttributes(&ObjectAttributes
,
2230 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2234 /* Create the section */
2235 Status
= ZwCreateSection(&SectionHandle
,
2242 if (!NT_SUCCESS(Status
)) goto Quickie
;
2244 /* Now get the section pointer */
2245 Status
= ObReferenceObjectByHandle(SectionHandle
,
2246 SECTION_MAP_EXECUTE
,
2247 MmSectionObjectType
,
2251 ZwClose(SectionHandle
);
2252 if (!NT_SUCCESS(Status
)) goto Quickie
;
2254 /* Check if this was supposed to be a session-load */
2257 /* We don't support session loading yet */
2258 DPRINT1("Unsupported Session-Load!\n");
2262 /* Check the loader list again, we should end up in the path below */
2267 /* We don't have a valid entry */
2271 /* Load the image */
2272 Status
= MiLoadImageSection(&Section
,
2277 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
2279 /* Get the size of the driver */
2280 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
2282 /* Make sure we're not being loaded into session space */
2285 /* Check for success */
2286 if (NT_SUCCESS(Status
))
2289 /* Support large pages for drivers */
2290 MiUseLargeDriverPage(DriverSize
/ PAGE_SIZE
,
2297 /* Dereference the section */
2298 ObDereferenceObject(Section
);
2302 /* Check for failure of the load earlier */
2303 if (!NT_SUCCESS(Status
)) goto Quickie
;
2305 /* Relocate the driver */
2306 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
2310 STATUS_CONFLICTING_ADDRESSES
,
2311 STATUS_INVALID_IMAGE_FORMAT
);
2312 if (!NT_SUCCESS(Status
)) goto Quickie
;
2315 /* Get the NT Header */
2316 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
2318 /* Calculate the size we'll need for the entry and allocate it */
2319 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
2321 sizeof(UNICODE_NULL
);
2323 /* Allocate the entry */
2324 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
2328 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2332 /* Setup the entry */
2333 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
2334 LdrEntry
->LoadCount
= 1;
2335 LdrEntry
->LoadedImports
= LoadedImports
;
2336 LdrEntry
->PatchInformation
= NULL
;
2338 /* Check the version */
2339 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
2340 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
2342 /* Mark this image as a native image */
2343 LdrEntry
->Flags
|= LDRP_ENTRY_NATIVE
;
2346 /* Setup the rest of the entry */
2347 LdrEntry
->DllBase
= ModuleLoadBase
;
2348 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
2349 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
2350 LdrEntry
->SizeOfImage
= DriverSize
;
2351 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
2352 LdrEntry
->SectionPointer
= Section
;
2354 /* Now write the DLL name */
2355 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
2356 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
2357 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
2359 /* Copy and null-terminate it */
2360 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
2363 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2365 /* Now allocate the full name */
2366 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2368 sizeof(UNICODE_NULL
),
2370 if (!LdrEntry
->FullDllName
.Buffer
)
2372 /* Don't fail, just set it to zero */
2373 LdrEntry
->FullDllName
.Length
= 0;
2374 LdrEntry
->FullDllName
.MaximumLength
= 0;
2379 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
2380 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
2382 /* Copy and null-terminate */
2383 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
2386 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2390 MiProcessLoaderEntry(LdrEntry
, TRUE
);
2392 /* Resolve imports */
2393 MissingApiName
= Buffer
;
2394 Status
= MiResolveImageReferences(ModuleLoadBase
,
2400 if (!NT_SUCCESS(Status
))
2403 MiProcessLoaderEntry(LdrEntry
, FALSE
);
2405 /* Check if we need to free the name */
2406 if (LdrEntry
->FullDllName
.Buffer
)
2409 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
2412 /* Free the entry itself */
2413 ExFreePoolWithTag(LdrEntry
, TAG_MODULE_OBJECT
);
2418 /* Update the loader entry */
2419 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
2420 LDRP_ENTRY_PROCESSED
|
2422 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
2423 LdrEntry
->LoadedImports
= LoadedImports
;
2425 /* FIXME: Call driver verifier's loader function */
2427 /* Write-protect the system image */
2428 MiWriteProtectSystemImage(LdrEntry
->DllBase
);
2430 /* Check if notifications are enabled */
2431 if (PsImageNotifyEnabled
)
2433 /* Fill out the notification data */
2434 ImageInfo
.Properties
= 0;
2435 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
2436 ImageInfo
.SystemModeImage
= TRUE
;
2437 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
2438 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
2439 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
2441 /* Send the notification */
2442 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
2445 #if defined(KDBG) || defined(_WINKD_)
2446 /* MiCacheImageSymbols doesn't detect rossym */
2449 /* Check if there's symbols */
2450 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
2453 /* Check if the system root is present */
2454 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
2455 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
2457 /* Add the system root */
2458 UnicodeTemp
= PrefixName
;
2459 UnicodeTemp
.Buffer
+= 11;
2460 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
2463 &SharedUserData
->NtSystemRoot
[2],
2468 /* Build the name */
2469 sprintf_nt(Buffer
, "%wZ", &BaseName
);
2472 /* Setup the ansi string */
2473 RtlInitString(&AnsiTemp
, Buffer
);
2475 /* Notify the debugger */
2476 DbgLoadImageSymbols(&AnsiTemp
,
2478 (ULONG_PTR
)ZwCurrentProcess());
2479 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
2482 /* Page the driver */
2483 ASSERT(Section
== NULL
);
2484 MiEnablePagingOfDriver(LdrEntry
);
2486 /* Return pointers */
2487 *ModuleObject
= LdrEntry
;
2488 *ImageBaseAddress
= LdrEntry
->DllBase
;
2491 /* Check if we have the lock acquired */
2494 /* Release the lock */
2495 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
2496 KeLeaveCriticalRegion();
2500 /* If we have a file handle, close it */
2501 if (FileHandle
) ZwClose(FileHandle
);
2503 /* Check if we had a prefix */
2504 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
2506 /* Free the name buffer and return status */
2507 ExFreePoolWithTag(Buffer
, TAG_LDR_WSTR
);
2511 PLDR_DATA_TABLE_ENTRY
2513 MiLookupDataTableEntry(IN PVOID Address
)
2515 PLDR_DATA_TABLE_ENTRY LdrEntry
, FoundEntry
= NULL
;
2516 PLIST_ENTRY NextEntry
;
2520 NextEntry
= PsLoadedModuleList
.Flink
;
2523 /* Get the loader entry */
2524 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2525 LDR_DATA_TABLE_ENTRY
,
2528 /* Check if the address matches */
2529 if ((Address
>= LdrEntry
->DllBase
) &&
2530 (Address
< (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
2531 LdrEntry
->SizeOfImage
)))
2534 FoundEntry
= LdrEntry
;
2539 NextEntry
= NextEntry
->Flink
;
2540 } while(NextEntry
!= &PsLoadedModuleList
);
2542 /* Return the entry */
2546 /* PUBLIC FUNCTIONS ***********************************************************/
2553 MmPageEntireDriver(IN PVOID AddressWithinSection
)
2555 PMMPTE StartPte
, EndPte
;
2556 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2559 /* Get the loader entry */
2560 LdrEntry
= MiLookupDataTableEntry(AddressWithinSection
);
2561 if (!LdrEntry
) return NULL
;
2563 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
2564 if ((MmDisablePagingExecutive
) || (LdrEntry
->SectionPointer
))
2566 /* Don't do anything, just return the base address */
2567 return LdrEntry
->DllBase
;
2570 /* Wait for active DPCs to finish before we page out the driver */
2571 KeFlushQueuedDpcs();
2573 /* Get the PTE range for the whole driver image */
2574 StartPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
);
2575 EndPte
= MiAddressToPte((ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
);
2577 /* Enable paging for the PTE range */
2578 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection
) == FALSE
);
2579 MiSetPagingOfDriver(StartPte
, EndPte
);
2581 /* Return the base address */
2582 return LdrEntry
->DllBase
;
2590 MmResetDriverPaging(IN PVOID AddressWithinSection
)
2600 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
2602 PVOID ProcAddress
= NULL
;
2603 ANSI_STRING AnsiRoutineName
;
2605 PLIST_ENTRY NextEntry
;
2606 PLDR_DATA_TABLE_ENTRY LdrEntry
;
2607 BOOLEAN Found
= FALSE
;
2608 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
2609 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
2612 /* Convert routine to ansi name */
2613 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
2616 if (!NT_SUCCESS(Status
)) return NULL
;
2619 KeEnterCriticalRegion();
2620 ExAcquireResourceSharedLite(&PsLoadedModuleResource
, TRUE
);
2622 /* Loop the loaded module list */
2623 NextEntry
= PsLoadedModuleList
.Flink
;
2624 while (NextEntry
!= &PsLoadedModuleList
)
2627 LdrEntry
= CONTAINING_RECORD(NextEntry
,
2628 LDR_DATA_TABLE_ENTRY
,
2631 /* Check if it's the kernel or HAL */
2632 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
2638 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
2645 /* Check if we found a valid binary */
2648 /* Find the procedure name */
2649 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
2652 /* Break out if we found it or if we already tried both modules */
2653 if (ProcAddress
) break;
2654 if (Modules
== 2) break;
2658 NextEntry
= NextEntry
->Flink
;
2661 /* Release the lock */
2662 ExReleaseResourceLite(&PsLoadedModuleResource
);
2663 KeLeaveCriticalRegion();
2665 /* Free the string and return */
2666 RtlFreeAnsiString(&AnsiRoutineName
);