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)
9 /* INCLUDES ******************************************************************/
15 /* GCC's incompetence strikes again */
18 sprintf_nt(IN PCHAR Buffer
,
24 vsprintf(Buffer
, Format
, ap
);
28 /* GLOBALS *******************************************************************/
30 LIST_ENTRY PsLoadedModuleList
;
31 KSPIN_LOCK PsLoadedModuleSpinLock
;
32 ULONG PsNtosImageBase
;
33 KMUTANT MmSystemLoadLock
;
34 extern ULONG NtGlobalFlag
;
36 /* FUNCTIONS *****************************************************************/
40 MiCacheImageSymbols(IN PVOID BaseAddress
)
43 PVOID DebugDirectory
= NULL
;
46 /* Make sure it's safe to access the image */
49 /* Get the debug directory */
50 DebugDirectory
= RtlImageDirectoryEntryToData(BaseAddress
,
52 IMAGE_DIRECTORY_ENTRY_DEBUG
,
61 /* Return the directory */
62 return DebugDirectory
;
67 MiFreeBootDriverMemory(PVOID BaseAddress
,
73 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
76 MmDeleteVirtualMapping(NULL
,
77 (PVOID
)((ULONG_PTR
)BaseAddress
+ i
* PAGE_SIZE
),
86 MiLoadImageSection(IN OUT PVOID
*SectionPtr
,
88 IN PUNICODE_STRING FileName
,
89 IN BOOLEAN SessionLoad
,
90 IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
92 PROS_SECTION_OBJECT Section
= *SectionPtr
;
98 LARGE_INTEGER SectionOffset
= {{0}};
99 BOOLEAN LoadSymbols
= FALSE
;
104 /* Detect session load */
108 DPRINT1("Session loading not yet supported!\n");
112 /* Not session load, shouldn't have an entry */
113 ASSERT(LdrEntry
== NULL
);
115 /* Attach to the system process */
116 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
118 /* Check if we need to load symbols */
119 if (NtGlobalFlag
& FLG_ENABLE_KDEBUG_SYMBOL_LOAD
)
123 NtGlobalFlag
&= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
127 Process
= PsGetCurrentProcess();
128 Status
= MmMapViewOfSection(Section
,
139 /* Re-enable the flag */
140 if (LoadSymbols
) NtGlobalFlag
|= FLG_ENABLE_KDEBUG_SYMBOL_LOAD
;
142 /* Check if we failed with distinguished status code */
143 if (Status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
145 /* Change it to something more generic */
146 Status
= STATUS_INVALID_IMAGE_FORMAT
;
149 /* Now check if we failed */
150 if (!NT_SUCCESS(Status
))
152 /* Detach and return */
153 KeUnstackDetachProcess(&ApcState
);
157 /* Get the driver size */
158 DriverSize
= Section
->ImageSection
->ImageSize
;
160 /* Allocate a virtual section for the module */
161 DriverBase
= MmAllocateSection(DriverSize
, NULL
);
162 *ImageBase
= DriverBase
;
165 RtlCopyMemory(DriverBase
, Base
, DriverSize
);
167 /* Now unmap the view */
168 Status
= MmUnmapViewOfSection(Process
, Base
);
169 ASSERT(NT_SUCCESS(Status
));
171 /* Detach and return status */
172 KeUnstackDetachProcess(&ApcState
);
178 MiDereferenceImports(IN PLOAD_IMPORTS ImportList
)
180 /* Check if there's no imports or if we're a boot driver */
181 if ((ImportList
== (PVOID
)-1) || (ImportList
== (PVOID
)-2))
183 /* Then there's nothing to do */
184 return STATUS_SUCCESS
;
187 /* Otherwise, FIXME */
188 DPRINT1("Imports not dereferenced!\n");
189 return STATUS_UNSUCCESSFUL
;
194 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
198 /* Check if there's no imports or we're a boot driver or only one entry */
199 if ((LdrEntry
->LoadedImports
== (PVOID
)-1) ||
200 (LdrEntry
->LoadedImports
== (PVOID
)-2) ||
201 ((ULONG_PTR
)LdrEntry
->LoadedImports
& 1))
207 /* Otherwise, free the import list */
208 ExFreePool(LdrEntry
->LoadedImports
);
213 MiFindExportedRoutineByName(IN PVOID DllBase
,
214 IN PANSI_STRING ExportName
)
217 PUSHORT OrdinalTable
;
218 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
219 LONG Low
= 0, Mid
= 0, High
, Ret
;
226 /* Get the export directory */
227 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
229 IMAGE_DIRECTORY_ENTRY_EXPORT
,
231 if (!ExportDirectory
) return NULL
;
233 /* Setup name tables */
234 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
235 ExportDirectory
->AddressOfNames
);
236 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
237 ExportDirectory
->AddressOfNameOrdinals
);
239 /* Do a binary search */
240 High
= ExportDirectory
->NumberOfNames
- 1;
243 /* Get new middle value */
244 Mid
= (Low
+ High
) >> 1;
247 Ret
= strcmp(ExportName
->Buffer
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
265 /* Check if we couldn't find it */
266 if (High
< Low
) return NULL
;
268 /* Otherwise, this is the ordinal */
269 Ordinal
= OrdinalTable
[Mid
];
271 /* Resolve the address and write it */
272 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
273 ExportDirectory
->AddressOfFunctions
);
274 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
277 ASSERT((Function
> (PVOID
)ExportDirectory
) &&
278 (Function
< (PVOID
)((ULONG_PTR
)ExportDirectory
+ ExportSize
)));
284 MiLocateExportName(IN PVOID DllBase
,
288 PUSHORT OrdinalTable
;
289 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
290 LONG Low
= 0, Mid
= 0, High
, Ret
;
297 /* Get the export directory */
298 ExportDirectory
= RtlImageDirectoryEntryToData(DllBase
,
300 IMAGE_DIRECTORY_ENTRY_EXPORT
,
302 if (!ExportDirectory
) return NULL
;
304 /* Setup name tables */
305 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
306 ExportDirectory
->AddressOfNames
);
307 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
308 ExportDirectory
->AddressOfNameOrdinals
);
310 /* Do a binary search */
311 High
= ExportDirectory
->NumberOfNames
- 1;
314 /* Get new middle value */
315 Mid
= (Low
+ High
) >> 1;
318 Ret
= strcmp(ExportName
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
336 /* Check if we couldn't find it */
337 if (High
< Low
) return NULL
;
339 /* Otherwise, this is the ordinal */
340 Ordinal
= OrdinalTable
[Mid
];
342 /* Resolve the address and write it */
343 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
344 ExportDirectory
->AddressOfFunctions
);
345 Function
= (PVOID
)((ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
]);
347 /* Check if the function is actually a forwarder */
348 if (((ULONG_PTR
)Function
> (ULONG_PTR
)ExportDirectory
) &&
349 ((ULONG_PTR
)Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
361 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
362 IN PLIST_ENTRY ListHead
)
364 PMM_DLL_INITIALIZE DllInit
;
366 /* Try to see if the image exports a DllInitialize routine */
367 DllInit
= (PMM_DLL_INITIALIZE
)MiLocateExportName(LdrEntry
->DllBase
,
369 if (!DllInit
) return STATUS_SUCCESS
;
372 DPRINT1("DllInitialize not called!\n");
373 return STATUS_UNSUCCESSFUL
;
378 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry
,
383 /* Acquire the lock */
384 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
386 /* Insert or remove from the list */
387 Insert
? InsertTailList(&PsLoadedModuleList
, &LdrEntry
->InLoadOrderLinks
) :
388 RemoveEntryList(&LdrEntry
->InLoadOrderLinks
);
390 /* Release the lock */
391 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);
396 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
401 ULONG_PTR OldBaseTop
, Delta
;
402 PLDR_DATA_TABLE_ENTRY LdrEntry
;
403 PLIST_ENTRY NextEntry
;
405 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
;
408 /* Calculate the top and delta */
409 OldBaseTop
= (ULONG_PTR
)OldBase
+ Size
- 1;
410 Delta
= (ULONG_PTR
)NewBase
- (ULONG_PTR
)OldBase
;
412 /* Loop the loader block */
413 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
414 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
415 NextEntry
= NextEntry
->Flink
)
417 /* Get the loader entry */
418 LdrEntry
= CONTAINING_RECORD(NextEntry
,
419 LDR_DATA_TABLE_ENTRY
,
422 /* Get the import table */
423 ImportDescriptor
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
425 IMAGE_DIRECTORY_ENTRY_IMPORT
,
427 if (!ImportDescriptor
) continue;
429 /* Make sure we have an IAT */
430 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry
->BaseDllName
);
431 while ((ImportDescriptor
->Name
) &&
432 (ImportDescriptor
->OriginalFirstThunk
))
434 /* Get the image thunk */
435 ImageThunk
= (PVOID
)((ULONG_PTR
)LdrEntry
->DllBase
+
436 ImportDescriptor
->FirstThunk
);
439 /* Check if it's within this module */
440 if ((*ImageThunk
>= (ULONG_PTR
)OldBase
) && (*ImageThunk
<= OldBaseTop
))
443 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
444 ImageThunk
, *ImageThunk
, *ImageThunk
+ Delta
);
445 *ImageThunk
+= Delta
;
448 /* Go to the next thunk */
452 /* Go to the next import */
460 MiSnapThunk(IN PVOID DllBase
,
462 IN PIMAGE_THUNK_DATA Name
,
463 IN PIMAGE_THUNK_DATA Address
,
464 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory
,
466 IN BOOLEAN SnapForwarder
,
467 OUT PCHAR
*MissingApi
)
472 PUSHORT OrdinalTable
;
473 PIMAGE_IMPORT_BY_NAME NameImport
;
475 ULONG Low
= 0, Mid
= 0, High
;
478 PCHAR MissingForwarder
;
479 CHAR NameBuffer
[MAXIMUM_FILENAME_LENGTH
];
482 UNICODE_STRING ForwarderName
;
483 PLIST_ENTRY NextEntry
;
484 PLDR_DATA_TABLE_ENTRY LdrEntry
;
485 ULONG ForwardExportSize
;
486 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory
;
487 PIMAGE_IMPORT_BY_NAME ForwardName
;
489 IMAGE_THUNK_DATA ForwardThunk
;
492 /* Check if this is an ordinal */
493 IsOrdinal
= IMAGE_SNAP_BY_ORDINAL(Name
->u1
.Ordinal
);
494 if ((IsOrdinal
) && !(SnapForwarder
))
496 /* Get the ordinal number and set it as missing */
497 Ordinal
= (USHORT
)(IMAGE_ORDINAL(Name
->u1
.Ordinal
) -
498 ExportDirectory
->Base
);
499 *MissingApi
= (PCHAR
)(ULONG_PTR
)Ordinal
;
503 /* Get the VA if we don't have to snap */
504 if (!SnapForwarder
) Name
->u1
.AddressOfData
+= (ULONG_PTR
)ImageBase
;
505 NameImport
= (PIMAGE_IMPORT_BY_NAME
)Name
->u1
.AddressOfData
;
507 /* Copy the procedure name */
509 (PCHAR
)&NameImport
->Name
[0],
510 MAXIMUM_FILENAME_LENGTH
- 1);
512 /* Setup name tables */
513 DPRINT("Import name: %s\n", NameImport
->Name
);
514 NameTable
= (PULONG
)((ULONG_PTR
)DllBase
+
515 ExportDirectory
->AddressOfNames
);
516 OrdinalTable
= (PUSHORT
)((ULONG_PTR
)DllBase
+
517 ExportDirectory
->AddressOfNameOrdinals
);
519 /* Get the hint and check if it's valid */
520 Hint
= NameImport
->Hint
;
521 if ((Hint
< ExportDirectory
->NumberOfNames
) &&
522 !(strcmp((PCHAR
) NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Hint
])))
524 /* We have a match, get the ordinal number from here */
525 Ordinal
= OrdinalTable
[Hint
];
529 /* Do a binary search */
530 High
= ExportDirectory
->NumberOfNames
- 1;
533 /* Get new middle value */
534 Mid
= (Low
+ High
) >> 1;
537 Ret
= strcmp((PCHAR
)NameImport
->Name
, (PCHAR
)DllBase
+ NameTable
[Mid
]);
555 /* Check if we couldn't find it */
556 if (High
< Low
) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
558 /* Otherwise, this is the ordinal */
559 Ordinal
= OrdinalTable
[Mid
];
563 /* Check if the ordinal is invalid */
564 if (Ordinal
>= ExportDirectory
->NumberOfFunctions
)
567 Status
= STATUS_DRIVER_ORDINAL_NOT_FOUND
;
571 /* In case the forwarder is missing */
572 MissingForwarder
= NameBuffer
;
574 /* Resolve the address and write it */
575 ExportTable
= (PULONG
)((ULONG_PTR
)DllBase
+
576 ExportDirectory
->AddressOfFunctions
);
577 Address
->u1
.Function
= (ULONG_PTR
)DllBase
+ ExportTable
[Ordinal
];
579 /* Assume success from now on */
580 Status
= STATUS_SUCCESS
;
582 /* Check if the function is actually a forwarder */
583 if ((Address
->u1
.Function
> (ULONG_PTR
)ExportDirectory
) &&
584 (Address
->u1
.Function
< ((ULONG_PTR
)ExportDirectory
+ ExportSize
)))
586 /* Now assume failure in case the forwarder doesn't exist */
587 Status
= STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
589 /* Build the forwarder name */
590 DllName
.Buffer
= (PCHAR
)Address
->u1
.Function
;
591 DllName
.Length
= strchr(DllName
.Buffer
, '.') -
594 DllName
.MaximumLength
= DllName
.Length
;
597 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName
,
601 /* We failed, just return an error */
605 /* Loop the module list */
606 NextEntry
= PsLoadedModuleList
.Flink
;
607 while (NextEntry
!= &PsLoadedModuleList
)
609 /* Get the loader entry */
610 LdrEntry
= CONTAINING_RECORD(NextEntry
,
611 LDR_DATA_TABLE_ENTRY
,
614 /* Check if it matches */
615 if (RtlPrefixString((PSTRING
)&ForwarderName
,
616 (PSTRING
)&LdrEntry
->BaseDllName
,
619 /* Get the forwarder export directory */
620 ForwardExportDirectory
=
621 RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
623 IMAGE_DIRECTORY_ENTRY_EXPORT
,
625 if (!ForwardExportDirectory
) break;
627 /* Allocate a name entry */
628 ForwardLength
= strlen(DllName
.Buffer
+ DllName
.Length
) +
630 ForwardName
= ExAllocatePoolWithTag(PagedPool
,
631 sizeof(*ForwardName
) +
634 if (!ForwardName
) break;
637 RtlCopyMemory(&ForwardName
->Name
[0],
638 DllName
.Buffer
+ DllName
.Length
,
640 ForwardName
->Hint
= 0;
642 /* Set the new address */
643 *(PULONG
)&ForwardThunk
.u1
.AddressOfData
= (ULONG
)ForwardName
;
645 /* Snap the forwarder */
646 Status
= MiSnapThunk(LdrEntry
->DllBase
,
650 ForwardExportDirectory
,
655 /* Free the forwarder name and set the thunk */
656 ExFreePool(ForwardName
);
657 Address
->u1
= ForwardThunk
.u1
;
661 /* Go to the next entry */
662 NextEntry
= NextEntry
->Flink
;
666 RtlFreeUnicodeString(&ForwarderName
);
676 MmUnloadSystemImage(IN PVOID ImageHandle
)
678 PLDR_DATA_TABLE_ENTRY LdrEntry
= ImageHandle
;
679 PVOID BaseAddress
= LdrEntry
->DllBase
;
681 ANSI_STRING TempName
;
682 BOOLEAN HadEntry
= FALSE
;
684 /* Acquire the loader lock */
685 KeEnterCriticalRegion();
686 KeWaitForSingleObject(&MmSystemLoadLock
,
692 /* Check if this driver was loaded at boot and didn't get imports parsed */
693 if (LdrEntry
->LoadedImports
== (PVOID
)-1) goto Done
;
695 /* We should still be alive */
696 ASSERT(LdrEntry
->LoadCount
!= 0);
697 LdrEntry
->LoadCount
--;
699 /* Check if we're still loaded */
700 if (LdrEntry
->LoadCount
) goto Done
;
702 /* We should cleanup... are symbols loaded */
703 if (LdrEntry
->Flags
& LDRP_DEBUG_SYMBOLS_LOADED
)
705 /* Create the ANSI name */
706 Status
= RtlUnicodeStringToAnsiString(&TempName
,
707 &LdrEntry
->BaseDllName
,
709 if (NT_SUCCESS(Status
))
711 /* Unload the symbols */
712 DbgUnLoadImageSymbols(&TempName
, BaseAddress
, -1);
713 RtlFreeAnsiString(&TempName
);
717 /* FIXME: Free the driver */
718 //MmFreeSection(LdrEntry->DllBase);
720 /* Check if we're linked in */
721 if (LdrEntry
->InLoadOrderLinks
.Flink
)
724 MiProcessLoaderEntry(LdrEntry
, FALSE
);
728 /* Dereference and clear the imports */
729 MiDereferenceImports(LdrEntry
->LoadedImports
);
730 MiClearImports(LdrEntry
);
732 /* Check if the entry needs to go away */
735 /* Check if it had a name */
736 if (LdrEntry
->FullDllName
.Buffer
)
739 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
742 /* Check if we had a section */
743 if (LdrEntry
->SectionPointer
)
746 ObDereferenceObject(LdrEntry
->SectionPointer
);
750 ExFreePool(LdrEntry
);
753 /* Release the system lock and return */
755 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
756 KeLeaveCriticalRegion();
757 return STATUS_SUCCESS
;
762 MiResolveImageReferences(IN PVOID ImageBase
,
763 IN PUNICODE_STRING ImageFileDirectory
,
764 IN PUNICODE_STRING NamePrefix OPTIONAL
,
765 OUT PCHAR
*MissingApi
,
766 OUT PWCHAR
*MissingDriver
,
767 OUT PLOAD_IMPORTS
*LoadImports
)
769 PCHAR MissingApiBuffer
= *MissingApi
, ImportName
;
770 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
, CurrentImport
;
771 ULONG ImportSize
, ImportCount
= 0, LoadedImportsSize
, ExportSize
;
772 PLOAD_IMPORTS LoadedImports
, NewImports
;
773 ULONG GdiLink
, NormalLink
, i
;
774 BOOLEAN ReferenceNeeded
, Loaded
;
775 ANSI_STRING TempString
;
776 UNICODE_STRING NameString
, DllName
;
777 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
, DllEntry
, ImportEntry
= NULL
;
778 PVOID ImportBase
, DllBase
;
779 PLIST_ENTRY NextEntry
;
780 PIMAGE_EXPORT_DIRECTORY ExportDirectory
;
782 PIMAGE_THUNK_DATA OrigThunk
, FirstThunk
;
784 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
785 __FUNCTION__
, ImageBase
, ImageFileDirectory
);
787 /* Assume no imports */
788 *LoadImports
= (PVOID
)-2;
790 /* Get the import descriptor */
791 ImportDescriptor
= RtlImageDirectoryEntryToData(ImageBase
,
793 IMAGE_DIRECTORY_ENTRY_IMPORT
,
795 if (!ImportDescriptor
) return STATUS_SUCCESS
;
797 /* Loop all imports to count them */
798 for (CurrentImport
= ImportDescriptor
;
799 (CurrentImport
->Name
) && (CurrentImport
->OriginalFirstThunk
);
806 /* Make sure we have non-zero imports */
809 /* Calculate and allocate the list we'll need */
810 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
811 LoadedImports
= ExAllocatePoolWithTag(PagedPool
,
816 /* Zero it and set the count */
817 RtlZeroMemory(LoadedImports
, LoadedImportsSize
);
818 LoadedImports
->Count
= ImportCount
;
824 LoadedImports
= NULL
;
827 /* Reset the import count and loop descriptors again */
828 ImportCount
= GdiLink
= NormalLink
= 0;
829 while ((ImportDescriptor
->Name
) && (ImportDescriptor
->OriginalFirstThunk
))
832 ImportName
= (PCHAR
)((ULONG_PTR
)ImageBase
+ ImportDescriptor
->Name
);
834 /* Check if this is a GDI driver */
836 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1));
838 /* We can also allow dxapi */
839 NormalLink
= NormalLink
|
840 ((_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) &&
841 (_strnicmp(ImportName
, "dxapi", sizeof("dxapi") - 1)));
843 /* Check if this is a valid GDI driver */
844 if ((GdiLink
) && (NormalLink
))
846 /* It's not, it's importing stuff it shouldn't be! */
847 MiDereferenceImports(LoadedImports
);
848 if (LoadedImports
) ExFreePool(LoadedImports
);
849 return STATUS_PROCEDURE_NOT_FOUND
;
852 /* Check if this is a "core" import, which doesn't get referenced */
853 if (!(_strnicmp(ImportName
, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
854 !(_strnicmp(ImportName
, "win32k", sizeof("win32k") - 1)) ||
855 !(_strnicmp(ImportName
, "hal", sizeof("hal") - 1)))
857 /* Don't reference this */
858 ReferenceNeeded
= FALSE
;
862 /* Reference these modules */
863 ReferenceNeeded
= TRUE
;
866 /* Now setup a unicode string for the import */
867 RtlInitAnsiString(&TempString
, ImportName
);
868 Status
= RtlAnsiStringToUnicodeString(&NameString
, &TempString
, TRUE
);
869 if (!NT_SUCCESS(Status
))
872 MiDereferenceImports(LoadedImports
);
873 if (LoadedImports
) ExFreePool(LoadedImports
);
877 /* We don't support name prefixes yet */
878 if (NamePrefix
) DPRINT1("Name Prefix not yet supported!\n");
880 /* Remember that we haven't loaded the import at this point */
885 /* Loop the driver list */
886 NextEntry
= PsLoadedModuleList
.Flink
;
887 while (NextEntry
!= &PsLoadedModuleList
)
889 /* Get the loader entry and compare the name */
890 LdrEntry
= CONTAINING_RECORD(NextEntry
,
891 LDR_DATA_TABLE_ENTRY
,
893 if (RtlEqualUnicodeString(&NameString
,
894 &LdrEntry
->BaseDllName
,
897 /* Get the base address */
898 ImportBase
= LdrEntry
->DllBase
;
900 /* Check if we haven't loaded yet, and we need references */
901 if (!(Loaded
) && (ReferenceNeeded
))
903 /* Make sure we're not already loading */
904 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
906 /* Increase the load count */
907 LdrEntry
->LoadCount
++;
911 /* Done, break out */
915 /* Go to the next entry */
916 NextEntry
= NextEntry
->Flink
;
919 /* Check if we haven't loaded the import yet */
922 /* Setup the import DLL name */
923 DllName
.MaximumLength
= NameString
.Length
+
924 ImageFileDirectory
->Length
+
925 sizeof(UNICODE_NULL
);
926 DllName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
927 DllName
.MaximumLength
,
931 /* Setup the base length and copy it */
932 DllName
.Length
= ImageFileDirectory
->Length
;
933 RtlCopyMemory(DllName
.Buffer
,
934 ImageFileDirectory
->Buffer
,
935 ImageFileDirectory
->Length
);
937 /* Now add the import name and null-terminate it */
938 RtlAppendStringToString((PSTRING
)&DllName
,
939 (PSTRING
)&NameString
);
940 DllName
.Buffer
[(DllName
.MaximumLength
- 1) / 2] = UNICODE_NULL
;
943 Status
= MmLoadSystemImage(&DllName
,
949 if (NT_SUCCESS(Status
))
951 /* We can free the DLL Name */
952 ExFreePool(DllName
.Buffer
);
956 /* Fill out the information for the error */
957 *MissingDriver
= DllName
.Buffer
;
958 *(PULONG
)MissingDriver
|= 1;
964 /* We're out of resources */
965 Status
= STATUS_INSUFFICIENT_RESOURCES
;
968 /* Check if we're OK until now */
969 if (NT_SUCCESS(Status
))
971 /* We're now loaded */
975 ASSERT(DllBase
= DllEntry
->DllBase
);
977 /* Call the initialization routines */
978 Status
= MmCallDllInitialize(DllEntry
, &PsLoadedModuleList
);
979 if (!NT_SUCCESS(Status
))
981 /* We failed, unload the image */
982 MmUnloadSystemImage(DllEntry
);
988 /* Check if we failed by here */
989 if (!NT_SUCCESS(Status
))
991 /* Cleanup and return */
992 RtlFreeUnicodeString(&NameString
);
993 MiDereferenceImports(LoadedImports
);
994 if (LoadedImports
) ExFreePool(LoadedImports
);
998 /* Loop again to make sure that everything is OK */
1002 /* Check if we're support to reference this import */
1003 if ((ReferenceNeeded
) && (LoadedImports
))
1005 /* Make sure we're not already loading */
1006 if (!(LdrEntry
->Flags
& LDRP_LOAD_IN_PROGRESS
))
1009 LoadedImports
->Entry
[ImportCount
] = LdrEntry
;
1014 /* Free the import name */
1015 RtlFreeUnicodeString(&NameString
);
1017 /* Set the missing driver name and get the export directory */
1018 *MissingDriver
= LdrEntry
->BaseDllName
.Buffer
;
1019 ExportDirectory
= RtlImageDirectoryEntryToData(ImportBase
,
1021 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1023 if (!ExportDirectory
)
1025 /* Cleanup and return */
1026 MiDereferenceImports(LoadedImports
);
1027 if (LoadedImports
) ExFreePool(LoadedImports
);
1028 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
;
1031 /* Make sure we have an IAT */
1032 if (ImportDescriptor
->OriginalFirstThunk
)
1034 /* Get the first thunks */
1035 OrigThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1036 ImportDescriptor
->OriginalFirstThunk
);
1037 FirstThunk
= (PVOID
)((ULONG_PTR
)ImageBase
+
1038 ImportDescriptor
->FirstThunk
);
1041 while (OrigThunk
->u1
.AddressOfData
)
1044 Status
= MiSnapThunk(ImportBase
,
1052 if (!NT_SUCCESS(Status
))
1054 /* Cleanup and return */
1055 MiDereferenceImports(LoadedImports
);
1056 if (LoadedImports
) ExFreePool(LoadedImports
);
1060 /* Reset the buffer */
1061 *MissingApi
= MissingApiBuffer
;
1065 /* Go to the next import */
1069 /* Check if we have an import list */
1072 /* Reset the count again, and loop entries*/
1074 for (i
= 0; i
< LoadedImports
->Count
; i
++)
1076 if (LoadedImports
->Entry
[i
])
1078 /* Got an entry, OR it with 1 in case it's the single entry */
1079 ImportEntry
= (PVOID
)((ULONG_PTR
)LoadedImports
->Entry
[i
] | 1);
1084 /* Check if we had no imports */
1087 /* Free the list and set it to no imports */
1088 ExFreePool(LoadedImports
);
1089 LoadedImports
= (PVOID
)-2;
1091 else if (ImportCount
== 1)
1093 /* Just one entry, we can free the table and only use our entry */
1094 ExFreePool(LoadedImports
);
1095 LoadedImports
= (PLOAD_IMPORTS
)ImportEntry
;
1097 else if (ImportCount
!= LoadedImports
->Count
)
1099 /* Allocate a new list */
1100 LoadedImportsSize
= ImportCount
* sizeof(PVOID
) + sizeof(SIZE_T
);
1101 NewImports
= ExAllocatePoolWithTag(PagedPool
,
1107 NewImports
->Count
= ImportCount
;
1109 /* Loop all the imports */
1110 for (i
= 0, ImportCount
= 0; i
< LoadedImports
->Count
; i
++)
1112 /* Make sure it's valid */
1113 if (LoadedImports
->Entry
[i
])
1116 NewImports
->Entry
[i
] = LoadedImports
->Entry
[i
];
1121 /* Free the old copy */
1122 ExFreePool(LoadedImports
);
1123 LoadedImports
= NewImports
;
1127 /* Return the list */
1128 *LoadImports
= LoadedImports
;
1131 /* Return success */
1132 return STATUS_SUCCESS
;
1137 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1139 PLIST_ENTRY NextEntry
;
1141 PIMAGE_NT_HEADERS NtHeader
;
1142 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1143 PIMAGE_FILE_HEADER FileHeader
;
1144 BOOLEAN ValidRelocs
;
1145 PIMAGE_DATA_DIRECTORY DataDirectory
;
1146 PVOID DllBase
, NewImageAddress
;
1149 /* Loop driver list */
1150 for (NextEntry
= LoaderBlock
->LoadOrderListHead
.Flink
;
1151 NextEntry
!= &LoaderBlock
->LoadOrderListHead
;
1152 NextEntry
= NextEntry
->Flink
)
1154 /* Get the loader entry and NT header */
1155 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1156 LDR_DATA_TABLE_ENTRY
,
1158 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
1161 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1163 (ULONG_PTR
)LdrEntry
->DllBase
+ LdrEntry
->SizeOfImage
,
1164 &LdrEntry
->FullDllName
);
1166 /* Skip kernel and HAL */
1167 /* ROS HACK: Skip BOOTVID/KDCOM too */
1169 if (i
<= 4) continue;
1171 /* Skip non-drivers */
1172 if (!NtHeader
) continue;
1174 /* Get the file header and make sure we can relocate */
1175 FileHeader
= &NtHeader
->FileHeader
;
1176 if (FileHeader
->Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
) continue;
1177 if (NtHeader
->OptionalHeader
.NumberOfRvaAndSizes
<
1178 IMAGE_DIRECTORY_ENTRY_BASERELOC
) continue;
1180 /* Everything made sense until now, check the relocation section too */
1181 DataDirectory
= &NtHeader
->OptionalHeader
.
1182 DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1183 if (!DataDirectory
->VirtualAddress
)
1185 /* We don't really have relocations */
1186 ValidRelocs
= FALSE
;
1190 /* Make sure the size is valid */
1191 if ((DataDirectory
->VirtualAddress
+ DataDirectory
->Size
) >
1192 LdrEntry
->SizeOfImage
)
1194 /* They're not, skip */
1198 /* We have relocations */
1202 /* Remember the original address */
1203 DllBase
= LdrEntry
->DllBase
;
1205 /* Allocate a virtual section for the module */
1206 NewImageAddress
= MmAllocateSection(LdrEntry
->SizeOfImage
, NULL
);
1207 if (!NewImageAddress
)
1209 /* Shouldn't happen */
1210 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1215 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase
, NewImageAddress
);
1216 ASSERT(ExpInitializationPhase
== 0);
1218 /* Now copy the entire driver over */
1219 RtlCopyMemory(NewImageAddress
, DllBase
, LdrEntry
->SizeOfImage
);
1222 ASSERT(*(PULONG
)NewImageAddress
== *(PULONG
)DllBase
);
1224 /* Set the image base to the address where the loader put it */
1225 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1226 NtHeader
= RtlImageNtHeader(NewImageAddress
);
1227 NtHeader
->OptionalHeader
.ImageBase
= (ULONG_PTR
)DllBase
;
1229 /* Check if we had relocations */
1232 /* Relocate the image */
1233 Status
= LdrRelocateImageWithBias(NewImageAddress
,
1237 STATUS_CONFLICTING_ADDRESSES
,
1238 STATUS_INVALID_IMAGE_FORMAT
);
1239 if (!NT_SUCCESS(Status
))
1241 /* This shouldn't happen */
1242 DPRINT1("Relocations failed!\n");
1247 /* Update the loader entry */
1248 LdrEntry
->DllBase
= NewImageAddress
;
1250 /* Update the thunks */
1251 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry
->BaseDllName
);
1252 MiUpdateThunks(LoaderBlock
,
1255 LdrEntry
->SizeOfImage
);
1257 /* Update the loader entry */
1258 LdrEntry
->Flags
|= 0x01000000;
1259 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)NewImageAddress
+
1260 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1261 LdrEntry
->SizeOfImage
= LdrEntry
->SizeOfImage
;
1263 /* Free the old copy */
1264 MiFreeBootDriverMemory(DllBase
, LdrEntry
->SizeOfImage
);
1270 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
1272 PLDR_DATA_TABLE_ENTRY LdrEntry
, NewEntry
;
1273 PLIST_ENTRY ListHead
, NextEntry
;
1276 /* Setup the loaded module list and lock */
1277 KeInitializeSpinLock(&PsLoadedModuleSpinLock
);
1278 InitializeListHead(&PsLoadedModuleList
);
1280 /* Get loop variables and the kernel entry */
1281 ListHead
= &LoaderBlock
->LoadOrderListHead
;
1282 NextEntry
= ListHead
->Flink
;
1283 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1284 LDR_DATA_TABLE_ENTRY
,
1286 PsNtosImageBase
= (ULONG
)LdrEntry
->DllBase
;
1288 /* Loop the loader block */
1289 while (NextEntry
!= ListHead
)
1291 /* Get the loader entry */
1292 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1293 LDR_DATA_TABLE_ENTRY
,
1296 /* FIXME: ROS HACK. Make sure this is a driver */
1297 if (!RtlImageNtHeader(LdrEntry
->DllBase
))
1299 /* Skip this entry */
1300 NextEntry
= NextEntry
->Flink
;
1304 /* Calculate the size we'll need and allocate a copy */
1305 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1306 LdrEntry
->BaseDllName
.MaximumLength
+
1307 sizeof(UNICODE_NULL
);
1308 NewEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_LDR_WSTR
);
1309 if (!NewEntry
) return FALSE
;
1311 /* Copy the entry over */
1312 *NewEntry
= *LdrEntry
;
1314 /* Allocate the name */
1315 NewEntry
->FullDllName
.Buffer
=
1316 ExAllocatePoolWithTag(PagedPool
,
1317 LdrEntry
->FullDllName
.MaximumLength
+
1318 sizeof(UNICODE_NULL
),
1320 if (!NewEntry
->FullDllName
.Buffer
) return FALSE
;
1322 /* Set the base name */
1323 NewEntry
->BaseDllName
.Buffer
= (PVOID
)(NewEntry
+ 1);
1325 /* Copy the full and base name */
1326 RtlCopyMemory(NewEntry
->FullDllName
.Buffer
,
1327 LdrEntry
->FullDllName
.Buffer
,
1328 LdrEntry
->FullDllName
.MaximumLength
);
1329 RtlCopyMemory(NewEntry
->BaseDllName
.Buffer
,
1330 LdrEntry
->BaseDllName
.Buffer
,
1331 LdrEntry
->BaseDllName
.MaximumLength
);
1333 /* Null-terminate the base name */
1334 NewEntry
->BaseDllName
.Buffer
[NewEntry
->BaseDllName
.Length
/
1335 sizeof(WCHAR
)] = UNICODE_NULL
;
1337 /* Insert the entry into the list */
1338 InsertTailList(&PsLoadedModuleList
, &NewEntry
->InLoadOrderLinks
);
1339 NextEntry
= NextEntry
->Flink
;
1342 /* Build the import lists for the boot drivers */
1343 //MiBuildImportsForBootDrivers();
1351 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress
)
1353 PIMAGE_NT_HEADERS NtHeader
;
1356 /* Get NT Headers */
1357 NtHeader
= RtlImageNtHeader(BaseAddress
);
1360 /* Check if this image is only safe for UP while we have 2+ CPUs */
1361 if ((KeNumberProcessors
> 1) &&
1362 (NtHeader
->FileHeader
.Characteristics
& IMAGE_FILE_UP_SYSTEM_ONLY
))
1369 /* Otherwise, it's safe */
1375 MmCheckSystemImage(IN HANDLE ImageHandle
,
1376 IN BOOLEAN PurgeSection
)
1379 HANDLE SectionHandle
;
1380 PVOID ViewBase
= NULL
;
1381 SIZE_T ViewSize
= 0;
1382 IO_STATUS_BLOCK IoStatusBlock
;
1383 FILE_STANDARD_INFORMATION FileStandardInfo
;
1384 KAPC_STATE ApcState
;
1387 /* Create a section for the DLL */
1388 Status
= ZwCreateSection(&SectionHandle
,
1389 SECTION_MAP_EXECUTE
,
1395 if (!NT_SUCCESS(Status
)) return Status
;
1397 /* Make sure we're in the system process */
1398 KeStackAttachProcess(&PsInitialSystemProcess
->Pcb
, &ApcState
);
1401 Status
= ZwMapViewOfSection(SectionHandle
,
1411 if (!NT_SUCCESS(Status
))
1413 /* We failed, close the handle and return */
1414 KeUnstackDetachProcess(&ApcState
);
1415 ZwClose(SectionHandle
);
1419 /* Now query image information */
1420 Status
= ZwQueryInformationFile(ImageHandle
,
1423 sizeof(FileStandardInfo
),
1424 FileStandardInformation
);
1425 if ( NT_SUCCESS(Status
) )
1427 /* First, verify the checksum */
1428 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase
,
1434 /* Set checksum failure */
1435 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
1438 /* Check that it's a valid SMP image if we have more then one CPU */
1439 if (!MmVerifyImageIsOkForMpUse(ViewBase
))
1441 /* Otherwise it's not the right image */
1442 Status
= STATUS_IMAGE_MP_UP_MISMATCH
;
1446 /* Unmap the section, close the handle, and return status */
1447 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
1448 KeUnstackDetachProcess(&ApcState
);
1449 ZwClose(SectionHandle
);
1455 MmLoadSystemImage(IN PUNICODE_STRING FileName
,
1456 IN PUNICODE_STRING NamePrefix OPTIONAL
,
1457 IN PUNICODE_STRING LoadedName OPTIONAL
,
1459 OUT PVOID
*ModuleObject
,
1460 OUT PVOID
*ImageBaseAddress
)
1462 PVOID ModuleLoadBase
= NULL
;
1464 HANDLE FileHandle
= NULL
;
1465 OBJECT_ATTRIBUTES ObjectAttributes
;
1466 IO_STATUS_BLOCK IoStatusBlock
;
1467 PIMAGE_NT_HEADERS NtHeader
;
1468 UNICODE_STRING BaseName
, BaseDirectory
, PrefixName
, UnicodeTemp
;
1469 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
1470 ULONG EntrySize
, DriverSize
;
1471 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
1472 PCHAR MissingApiName
, Buffer
;
1473 PWCHAR MissingDriverName
;
1474 HANDLE SectionHandle
;
1475 ACCESS_MASK DesiredAccess
;
1476 PVOID Section
= NULL
;
1477 BOOLEAN LockOwned
= FALSE
;
1478 PLIST_ENTRY NextEntry
;
1479 IMAGE_INFO ImageInfo
;
1480 ANSI_STRING AnsiTemp
;
1483 /* Detect session-load */
1487 ASSERT(NamePrefix
== NULL
);
1488 ASSERT(LoadedName
== NULL
);
1490 /* Make sure the process is in session too */
1491 if (!PsGetCurrentProcess()->ProcessInSession
) return STATUS_NO_MEMORY
;
1494 if (ModuleObject
) *ModuleObject
= NULL
;
1495 if (ImageBaseAddress
) *ImageBaseAddress
= NULL
;
1497 /* Allocate a buffer we'll use for names */
1498 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
1499 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1501 /* Check for a separator */
1502 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
1507 /* Loop the path until we get to the base name */
1508 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
1509 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
1511 /* Get the length */
1512 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
1513 BaseLength
*= sizeof(WCHAR
);
1515 /* Setup the string */
1516 BaseName
.Length
= (USHORT
)BaseLength
;
1517 BaseName
.Buffer
= p
;
1521 /* Otherwise, we already have a base name */
1522 BaseName
.Length
= FileName
->Length
;
1523 BaseName
.Buffer
= FileName
->Buffer
;
1526 /* Setup the maximum length */
1527 BaseName
.MaximumLength
= BaseName
.Length
;
1529 /* Now compute the base directory */
1530 BaseDirectory
= *FileName
;
1531 BaseDirectory
.Length
-= BaseName
.Length
;
1532 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
1534 /* And the prefix, which for now is just the name itself */
1535 PrefixName
= *FileName
;
1537 /* Check if we have a prefix */
1538 if (NamePrefix
) DPRINT1("Prefixed images are not yet supported!\n");
1540 /* Check if we already have a name, use it instead */
1541 if (LoadedName
) BaseName
= *LoadedName
;
1543 /* Acquire the load lock */
1545 ASSERT(LockOwned
== FALSE
);
1547 KeEnterCriticalRegion();
1548 KeWaitForSingleObject(&MmSystemLoadLock
,
1554 /* Scan the module list */
1555 NextEntry
= PsLoadedModuleList
.Flink
;
1556 while (NextEntry
!= &PsLoadedModuleList
)
1558 /* Get the entry and compare the names */
1559 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1560 LDR_DATA_TABLE_ENTRY
,
1562 if (RtlEqualUnicodeString(&PrefixName
, &LdrEntry
->FullDllName
, TRUE
))
1564 /* Found it, break out */
1569 NextEntry
= NextEntry
->Flink
;
1572 /* Check if we found the image */
1573 if (NextEntry
!= &PsLoadedModuleList
)
1575 /* Check if we had already mapped a section */
1578 /* Dereference and clear */
1579 ObDereferenceObject(Section
);
1583 /* Check if this was supposed to be a session load */
1586 /* It wasn't, so just return the data */
1587 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1588 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1589 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1593 /* We don't support session loading yet */
1594 DPRINT1("Unsupported Session-Load!\n");
1603 /* It wasn't loaded, and we didn't have a previous attempt */
1604 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1605 KeLeaveCriticalRegion();
1608 /* Check if KD is enabled */
1609 if ((KdDebuggerEnabled
) && !(KdDebuggerNotPresent
))
1611 /* FIXME: Attempt to get image from KD */
1614 /* We don't have a valid entry */
1617 /* Setup image attributes */
1618 InitializeObjectAttributes(&ObjectAttributes
,
1620 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1624 /* Open the image */
1625 Status
= ZwOpenFile(&FileHandle
,
1629 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1631 if (!NT_SUCCESS(Status
)) goto Quickie
;
1634 Status
= MmCheckSystemImage(FileHandle
, FALSE
);
1635 if ((Status
== STATUS_IMAGE_CHECKSUM_MISMATCH
) ||
1636 (Status
== STATUS_IMAGE_MP_UP_MISMATCH
) ||
1637 (Status
== STATUS_INVALID_IMAGE_FORMAT
))
1643 /* Check if this is a session-load */
1646 /* Then we only need read and execute */
1647 DesiredAccess
= SECTION_MAP_READ
| SECTION_MAP_EXECUTE
;
1651 /* Otherwise, we can allow write access */
1652 DesiredAccess
= SECTION_ALL_ACCESS
;
1655 /* Initialize the attributes for the section */
1656 InitializeObjectAttributes(&ObjectAttributes
,
1658 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1662 /* Create the section */
1663 Status
= ZwCreateSection(&SectionHandle
,
1670 if (!NT_SUCCESS(Status
)) goto Quickie
;
1672 /* Now get the section pointer */
1673 Status
= ObReferenceObjectByHandle(SectionHandle
,
1674 SECTION_MAP_EXECUTE
,
1675 MmSectionObjectType
,
1679 ZwClose(SectionHandle
);
1680 if (!NT_SUCCESS(Status
)) goto Quickie
;
1682 /* Check if this was supposed to be a session-load */
1685 /* We don't support session loading yet */
1686 DPRINT1("Unsupported Session-Load!\n");
1690 /* Check the loader list again, we should end up in the path below */
1695 /* We don't have a valid entry */
1699 /* Load the image */
1700 Status
= MiLoadImageSection(&Section
,
1705 ASSERT(Status
!= STATUS_ALREADY_COMMITTED
);
1707 /* Get the size of the driver */
1708 DriverSize
= ((PROS_SECTION_OBJECT
)Section
)->ImageSection
->ImageSize
;
1710 /* Make sure we're not being loaded into session space */
1713 /* Check for success */
1714 if (NT_SUCCESS(Status
))
1716 /* FIXME: Support large pages for drivers */
1719 /* Dereference the section */
1720 ObDereferenceObject(Section
);
1724 /* Get the NT Header */
1725 NtHeader
= RtlImageNtHeader(ModuleLoadBase
);
1727 /* Relocate the driver */
1728 Status
= LdrRelocateImageWithBias(ModuleLoadBase
,
1732 STATUS_CONFLICTING_ADDRESSES
,
1733 STATUS_INVALID_IMAGE_FORMAT
);
1734 if (!NT_SUCCESS(Status
)) goto Quickie
;
1736 /* Calculate the size we'll need for the entry and allocate it */
1737 EntrySize
= sizeof(LDR_DATA_TABLE_ENTRY
) +
1739 sizeof(UNICODE_NULL
);
1741 /* Allocate the entry */
1742 LdrEntry
= ExAllocatePoolWithTag(NonPagedPool
, EntrySize
, TAG_MODULE_OBJECT
);
1746 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1750 /* Setup the entry */
1751 LdrEntry
->Flags
= LDRP_LOAD_IN_PROGRESS
;
1752 LdrEntry
->LoadCount
= 1;
1753 LdrEntry
->LoadedImports
= LoadedImports
;
1754 LdrEntry
->PatchInformation
= NULL
;
1756 /* Check the version */
1757 if ((NtHeader
->OptionalHeader
.MajorOperatingSystemVersion
>= 5) &&
1758 (NtHeader
->OptionalHeader
.MajorImageVersion
>= 5))
1760 /* Mark this image as a native image */
1761 LdrEntry
->Flags
|= 0x80000000;
1764 /* Setup the rest of the entry */
1765 LdrEntry
->DllBase
= ModuleLoadBase
;
1766 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)ModuleLoadBase
+
1767 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
1768 LdrEntry
->SizeOfImage
= DriverSize
;
1769 LdrEntry
->CheckSum
= NtHeader
->OptionalHeader
.CheckSum
;
1770 LdrEntry
->SectionPointer
= Section
;
1772 /* Now write the DLL name */
1773 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)(LdrEntry
+ 1);
1774 LdrEntry
->BaseDllName
.Length
= BaseName
.Length
;
1775 LdrEntry
->BaseDllName
.MaximumLength
= BaseName
.Length
;
1777 /* Copy and null-terminate it */
1778 RtlCopyMemory(LdrEntry
->BaseDllName
.Buffer
,
1781 LdrEntry
->BaseDllName
.Buffer
[BaseName
.Length
/ 2] = UNICODE_NULL
;
1783 /* Now allocate the full name */
1784 LdrEntry
->FullDllName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1786 sizeof(UNICODE_NULL
),
1788 if (!LdrEntry
->FullDllName
.Buffer
)
1790 /* Don't fail, just set it to zero */
1791 LdrEntry
->FullDllName
.Length
= 0;
1792 LdrEntry
->FullDllName
.MaximumLength
= 0;
1797 LdrEntry
->FullDllName
.Length
= PrefixName
.Length
;
1798 LdrEntry
->FullDllName
.MaximumLength
= PrefixName
.Length
;
1800 /* Copy and null-terminate */
1801 RtlCopyMemory(LdrEntry
->FullDllName
.Buffer
,
1804 LdrEntry
->FullDllName
.Buffer
[PrefixName
.Length
/ 2] = UNICODE_NULL
;
1808 MiProcessLoaderEntry(LdrEntry
, TRUE
);
1810 /* Resolve imports */
1811 MissingApiName
= Buffer
;
1812 Status
= MiResolveImageReferences(ModuleLoadBase
,
1818 if (!NT_SUCCESS(Status
))
1821 MiProcessLoaderEntry(LdrEntry
, FALSE
);
1823 /* Check if we need to free the name */
1824 if (LdrEntry
->FullDllName
.Buffer
)
1827 ExFreePool(LdrEntry
->FullDllName
.Buffer
);
1830 /* Free the entry itself */
1831 ExFreePool(LdrEntry
);
1836 /* Update the loader entry */
1837 LdrEntry
->Flags
|= (LDRP_SYSTEM_MAPPED
|
1838 LDRP_ENTRY_PROCESSED
|
1840 LdrEntry
->Flags
&= ~LDRP_LOAD_IN_PROGRESS
;
1841 LdrEntry
->LoadedImports
= LoadedImports
;
1843 /* FIXME: Apply driver verifier */
1845 /* FIXME: Write-protect the system image */
1847 /* Check if notifications are enabled */
1848 if (PsImageNotifyEnabled
)
1850 /* Fill out the notification data */
1851 ImageInfo
.Properties
= 0;
1852 ImageInfo
.ImageAddressingMode
= IMAGE_ADDRESSING_MODE_32BIT
;
1853 ImageInfo
.SystemModeImage
= TRUE
;
1854 ImageInfo
.ImageSize
= LdrEntry
->SizeOfImage
;
1855 ImageInfo
.ImageBase
= LdrEntry
->DllBase
;
1856 ImageInfo
.ImageSectionNumber
= ImageInfo
.ImageSelector
= 0;
1858 /* Send the notification */
1859 PspRunLoadImageNotifyRoutines(FileName
, NULL
, &ImageInfo
);
1862 /* Check if there's symbols */
1863 if (MiCacheImageSymbols(LdrEntry
->DllBase
))
1865 /* Check if the system root is present */
1866 if ((PrefixName
.Length
> (11 * sizeof(WCHAR
))) &&
1867 !(_wcsnicmp(PrefixName
.Buffer
, L
"\\SystemRoot", 11)))
1869 /* Add the system root */
1870 UnicodeTemp
= PrefixName
;
1871 UnicodeTemp
.Buffer
+= 11;
1872 UnicodeTemp
.Length
-= (11 * sizeof(WCHAR
));
1875 &SharedUserData
->NtSystemRoot
[2],
1880 /* Build the name */
1881 sprintf_nt(Buffer
, "%wZ", &BaseName
);
1884 /* Setup the ansi string */
1885 RtlInitString(&AnsiTemp
, Buffer
);
1887 /* Notify the debugger */
1888 DbgLoadImageSymbols(&AnsiTemp
, LdrEntry
->DllBase
, -1);
1889 LdrEntry
->Flags
|= LDRP_DEBUG_SYMBOLS_LOADED
;
1892 /* FIXME: Page the driver */
1893 ASSERT(Section
== NULL
);
1895 /* Return pointers */
1896 if (ModuleObject
) *ModuleObject
= LdrEntry
;
1897 if (ImageBaseAddress
) *ImageBaseAddress
= LdrEntry
->DllBase
;
1900 /* If we have a file handle, close it */
1901 if (FileHandle
) ZwClose(FileHandle
);
1903 /* Check if we have the lock acquired */
1906 /* Release the lock */
1907 KeReleaseMutant(&MmSystemLoadLock
, 1, FALSE
, FALSE
);
1908 KeLeaveCriticalRegion();
1912 /* Check if we had a prefix */
1913 if (NamePrefix
) ExFreePool(PrefixName
.Buffer
);
1915 /* Free the name buffer and return status */
1925 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName
)
1927 PVOID ProcAddress
= NULL
;
1928 ANSI_STRING AnsiRoutineName
;
1930 PLIST_ENTRY NextEntry
;
1931 extern LIST_ENTRY PsLoadedModuleList
;
1932 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1933 BOOLEAN Found
= FALSE
;
1934 UNICODE_STRING KernelName
= RTL_CONSTANT_STRING(L
"ntoskrnl.exe");
1935 UNICODE_STRING HalName
= RTL_CONSTANT_STRING(L
"hal.dll");
1938 /* Convert routine to ansi name */
1939 Status
= RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
1942 if (!NT_SUCCESS(Status
)) return NULL
;
1945 KeEnterCriticalRegion();
1947 /* Loop the loaded module list */
1948 NextEntry
= PsLoadedModuleList
.Flink
;
1949 while (NextEntry
!= &PsLoadedModuleList
)
1952 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1953 LDR_DATA_TABLE_ENTRY
,
1956 /* Check if it's the kernel or HAL */
1957 if (RtlEqualUnicodeString(&KernelName
, &LdrEntry
->BaseDllName
, TRUE
))
1963 else if (RtlEqualUnicodeString(&HalName
, &LdrEntry
->BaseDllName
, TRUE
))
1970 /* Check if we found a valid binary */
1973 /* Find the procedure name */
1974 ProcAddress
= MiFindExportedRoutineByName(LdrEntry
->DllBase
,
1977 /* Break out if we found it or if we already tried both modules */
1978 if (ProcAddress
) break;
1979 if (Modules
== 2) break;
1983 NextEntry
= NextEntry
->Flink
;
1986 /* Release the lock */
1987 KeLeaveCriticalRegion();
1989 /* Free the string and return */
1990 RtlFreeAnsiString(&AnsiRoutineName
);