[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / sysldr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sysldr.c
5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * ReactOS Portable Systems Group
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* GCC's incompetence strikes again */
20 __inline
21 VOID
22 sprintf_nt(IN PCHAR Buffer,
23 IN PCHAR Format,
24 IN ...)
25 {
26 va_list ap;
27 va_start(ap, Format);
28 vsprintf(Buffer, Format, ap);
29 va_end(ap);
30 }
31
32 /* GLOBALS ********************************************************************/
33
34 LIST_ENTRY PsLoadedModuleList;
35 LIST_ENTRY MmLoadedUserImageList;
36 KSPIN_LOCK PsLoadedModuleSpinLock;
37 ERESOURCE PsLoadedModuleResource;
38 ULONG_PTR PsNtosImageBase;
39 KMUTANT MmSystemLoadLock;
40
41 PFN_NUMBER MmTotalSystemDriverPages;
42
43 PVOID MmUnloadedDrivers;
44 PVOID MmLastUnloadedDrivers;
45
46 BOOLEAN MmMakeLowMemory;
47 BOOLEAN MmEnforceWriteProtection = TRUE;
48
49 PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte;
50 ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
51 ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
52
53 /* FUNCTIONS ******************************************************************/
54
55 PVOID
56 NTAPI
57 MiCacheImageSymbols(IN PVOID BaseAddress)
58 {
59 ULONG DebugSize;
60 PVOID DebugDirectory = NULL;
61 PAGED_CODE();
62
63 /* Make sure it's safe to access the image */
64 _SEH2_TRY
65 {
66 /* Get the debug directory */
67 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
68 TRUE,
69 IMAGE_DIRECTORY_ENTRY_DEBUG,
70 &DebugSize);
71 }
72 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
73 {
74 /* Nothing */
75 }
76 _SEH2_END;
77
78 /* Return the directory */
79 return DebugDirectory;
80 }
81
82 NTSTATUS
83 NTAPI
84 MiLoadImageSection(IN OUT PVOID *SectionPtr,
85 OUT PVOID *ImageBase,
86 IN PUNICODE_STRING FileName,
87 IN BOOLEAN SessionLoad,
88 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
89 {
90 PROS_SECTION_OBJECT Section = *SectionPtr;
91 NTSTATUS Status;
92 PEPROCESS Process;
93 PVOID Base = NULL;
94 SIZE_T ViewSize = 0;
95 KAPC_STATE ApcState;
96 LARGE_INTEGER SectionOffset = {{0, 0}};
97 BOOLEAN LoadSymbols = FALSE;
98 PFN_COUNT PteCount;
99 PMMPTE PointerPte, LastPte;
100 PVOID DriverBase;
101 MMPTE TempPte;
102 PAGED_CODE();
103
104 /* Detect session load */
105 if (SessionLoad)
106 {
107 /* Fail */
108 DPRINT1("Session loading not yet supported!\n");
109 while (TRUE);
110 }
111
112 /* Not session load, shouldn't have an entry */
113 ASSERT(LdrEntry == NULL);
114
115 /* Attach to the system process */
116 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
117
118 /* Check if we need to load symbols */
119 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
120 {
121 /* Yes we do */
122 LoadSymbols = TRUE;
123 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
124 }
125
126 /* Map the driver */
127 Process = PsGetCurrentProcess();
128 Status = MmMapViewOfSection(Section,
129 Process,
130 &Base,
131 0,
132 0,
133 &SectionOffset,
134 &ViewSize,
135 ViewUnmap,
136 0,
137 PAGE_EXECUTE);
138
139 /* Re-enable the flag */
140 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
141
142 /* Check if we failed with distinguished status code */
143 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
144 {
145 /* Change it to something more generic */
146 Status = STATUS_INVALID_IMAGE_FORMAT;
147 }
148
149 /* Now check if we failed */
150 if (!NT_SUCCESS(Status))
151 {
152 /* Detach and return */
153 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status);
154 KeUnstackDetachProcess(&ApcState);
155 return Status;
156 }
157
158 /* Reserve system PTEs needed */
159 PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
160 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
161 if (!PointerPte)
162 {
163 DPRINT1("MiReserveSystemPtes failed\n");
164 KeUnstackDetachProcess(&ApcState);
165 return STATUS_INSUFFICIENT_RESOURCES;
166 }
167
168 /* New driver base */
169 LastPte = PointerPte + PteCount;
170 DriverBase = MiPteToAddress(PointerPte);
171
172 /* The driver is here */
173 *ImageBase = DriverBase;
174 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount);
175
176 /* Loop the new driver PTEs */
177 TempPte = ValidKernelPte;
178 while (PointerPte < LastPte)
179 {
180 /* Allocate a page */
181 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
182 #if MI_TRACE_PFNS
183 PWCHAR pos = NULL;
184 ULONG len = 0;
185 if (FileName->Buffer)
186 {
187 pos = wcsrchr(FileName->Buffer, '\\');
188 len = wcslen(pos) * sizeof(WCHAR);
189 if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
190 }
191 #endif
192 TempPte.u.Hard.PageFrameNumber = MiAllocatePfn(PointerPte, MM_EXECUTE);
193
194 /* Write it */
195 MI_WRITE_VALID_PTE(PointerPte, TempPte);
196
197 /* Move on */
198 PointerPte++;
199 }
200
201 /* Copy the image */
202 RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
203
204 /* Now unmap the view */
205 Status = MmUnmapViewOfSection(Process, Base);
206 ASSERT(NT_SUCCESS(Status));
207
208 /* Detach and return status */
209 KeUnstackDetachProcess(&ApcState);
210 return Status;
211 }
212
213 PVOID
214 NTAPI
215 MiLocateExportName(IN PVOID DllBase,
216 IN PCHAR ExportName)
217 {
218 PULONG NameTable;
219 PUSHORT OrdinalTable;
220 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
221 LONG Low = 0, Mid = 0, High, Ret;
222 USHORT Ordinal;
223 PVOID Function;
224 ULONG ExportSize;
225 PULONG ExportTable;
226 PAGED_CODE();
227
228 /* Get the export directory */
229 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
230 TRUE,
231 IMAGE_DIRECTORY_ENTRY_EXPORT,
232 &ExportSize);
233 if (!ExportDirectory) return NULL;
234
235 /* Setup name tables */
236 NameTable = (PULONG)((ULONG_PTR)DllBase +
237 ExportDirectory->AddressOfNames);
238 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
239 ExportDirectory->AddressOfNameOrdinals);
240
241 /* Do a binary search */
242 High = ExportDirectory->NumberOfNames - 1;
243 while (High >= Low)
244 {
245 /* Get new middle value */
246 Mid = (Low + High) >> 1;
247
248 /* Compare name */
249 Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
250 if (Ret < 0)
251 {
252 /* Update high */
253 High = Mid - 1;
254 }
255 else if (Ret > 0)
256 {
257 /* Update low */
258 Low = Mid + 1;
259 }
260 else
261 {
262 /* We got it */
263 break;
264 }
265 }
266
267 /* Check if we couldn't find it */
268 if (High < Low) return NULL;
269
270 /* Otherwise, this is the ordinal */
271 Ordinal = OrdinalTable[Mid];
272
273 /* Resolve the address and write it */
274 ExportTable = (PULONG)((ULONG_PTR)DllBase +
275 ExportDirectory->AddressOfFunctions);
276 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
277
278 /* Check if the function is actually a forwarder */
279 if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
280 ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
281 {
282 /* It is, fail */
283 return NULL;
284 }
285
286 /* We found it */
287 return Function;
288 }
289
290 NTSTATUS
291 NTAPI
292 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
293 IN PLIST_ENTRY ListHead)
294 {
295 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
296 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
297 PMM_DLL_INITIALIZE DllInit;
298 UNICODE_STRING RegPath, ImportName;
299 NTSTATUS Status;
300
301 /* Try to see if the image exports a DllInitialize routine */
302 DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
303 "DllInitialize");
304 if (!DllInit) return STATUS_SUCCESS;
305
306 /* Do a temporary copy of BaseDllName called ImportName
307 * because we'll alter the length of the string
308 */
309 ImportName.Length = LdrEntry->BaseDllName.Length;
310 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
311 ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
312
313 /* Obtain the path to this dll's service in the registry */
314 RegPath.MaximumLength = ServicesKeyName.Length +
315 ImportName.Length + sizeof(UNICODE_NULL);
316 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
317 RegPath.MaximumLength,
318 TAG_LDR_WSTR);
319
320 /* Check if this allocation was unsuccessful */
321 if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
322
323 /* Build and append the service name itself */
324 RegPath.Length = ServicesKeyName.Length;
325 RtlCopyMemory(RegPath.Buffer,
326 ServicesKeyName.Buffer,
327 ServicesKeyName.Length);
328
329 /* Check if there is a dot in the filename */
330 if (wcschr(ImportName.Buffer, L'.'))
331 {
332 /* Remove the extension */
333 ImportName.Length = (USHORT)(wcschr(ImportName.Buffer, L'.') -
334 ImportName.Buffer) * sizeof(WCHAR);
335 }
336
337 /* Append service name (the basename without extension) */
338 RtlAppendUnicodeStringToString(&RegPath, &ImportName);
339
340 /* Now call the DllInit func */
341 DPRINT("Calling DllInit(%wZ)\n", &RegPath);
342 Status = DllInit(&RegPath);
343
344 /* Clean up */
345 ExFreePoolWithTag(RegPath.Buffer, TAG_LDR_WSTR);
346
347 /* Return status value which DllInitialize returned */
348 return Status;
349 }
350
351 BOOLEAN
352 NTAPI
353 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
354 {
355 NTSTATUS Status;
356 PMM_DLL_UNLOAD Func;
357 PAGED_CODE();
358
359 /* Get the unload routine */
360 Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload");
361 if (!Func) return FALSE;
362
363 /* Call it and check for success */
364 Status = Func();
365 if (!NT_SUCCESS(Status)) return FALSE;
366
367 /* Lie about the load count so we can unload the image */
368 ASSERT(LdrEntry->LoadCount == 0);
369 LdrEntry->LoadCount = 1;
370
371 /* Unload it and return true */
372 MmUnloadSystemImage(LdrEntry);
373 return TRUE;
374 }
375
376 NTSTATUS
377 NTAPI
378 MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
379 {
380 SIZE_T i;
381 LOAD_IMPORTS SingleEntry;
382 PLDR_DATA_TABLE_ENTRY LdrEntry;
383 PVOID CurrentImports;
384 PAGED_CODE();
385
386 /* Check if there's no imports or if we're a boot driver */
387 if ((ImportList == MM_SYSLDR_NO_IMPORTS) ||
388 (ImportList == MM_SYSLDR_BOOT_LOADED) ||
389 (ImportList->Count == 0))
390 {
391 /* Then there's nothing to do */
392 return STATUS_SUCCESS;
393 }
394
395 /* Check for single-entry */
396 if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY)
397 {
398 /* Set it up */
399 SingleEntry.Count = 1;
400 SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY);
401
402 /* Use this as the import list */
403 ImportList = &SingleEntry;
404 }
405
406 /* Loop the import list */
407 for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++)
408 {
409 /* Get the entry */
410 LdrEntry = ImportList->Entry[i];
411 DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName);
412
413 /* Skip boot loaded images */
414 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue;
415
416 /* Dereference the entry */
417 ASSERT(LdrEntry->LoadCount >= 1);
418 if (!--LdrEntry->LoadCount)
419 {
420 /* Save the import data in case unload fails */
421 CurrentImports = LdrEntry->LoadedImports;
422
423 /* This is the last entry */
424 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
425 if (MiCallDllUnloadAndUnloadDll(LdrEntry))
426 {
427 /* Unloading worked, parse this DLL's imports too */
428 MiDereferenceImports(CurrentImports);
429
430 /* Check if we had valid imports */
431 if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) ||
432 (CurrentImports != MM_SYSLDR_NO_IMPORTS) ||
433 !((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
434 {
435 /* Free them */
436 ExFreePoolWithTag(CurrentImports, TAG_LDR_IMPORTS);
437 }
438 }
439 else
440 {
441 /* Unload failed, restore imports */
442 LdrEntry->LoadedImports = CurrentImports;
443 }
444 }
445 }
446
447 /* Done */
448 return STATUS_SUCCESS;
449 }
450
451 VOID
452 NTAPI
453 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
454 {
455 PAGED_CODE();
456
457 /* Check if there's no imports or we're a boot driver or only one entry */
458 if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) ||
459 (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) ||
460 ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
461 {
462 /* Nothing to do */
463 return;
464 }
465
466 /* Otherwise, free the import list */
467 ExFreePoolWithTag(LdrEntry->LoadedImports, TAG_LDR_IMPORTS);
468 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
469 }
470
471 PVOID
472 NTAPI
473 MiFindExportedRoutineByName(IN PVOID DllBase,
474 IN PANSI_STRING ExportName)
475 {
476 PULONG NameTable;
477 PUSHORT OrdinalTable;
478 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
479 LONG Low = 0, Mid = 0, High, Ret;
480 USHORT Ordinal;
481 PVOID Function;
482 ULONG ExportSize;
483 PULONG ExportTable;
484 PAGED_CODE();
485
486 /* Get the export directory */
487 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
488 TRUE,
489 IMAGE_DIRECTORY_ENTRY_EXPORT,
490 &ExportSize);
491 if (!ExportDirectory) return NULL;
492
493 /* Setup name tables */
494 NameTable = (PULONG)((ULONG_PTR)DllBase +
495 ExportDirectory->AddressOfNames);
496 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
497 ExportDirectory->AddressOfNameOrdinals);
498
499 /* Do a binary search */
500 High = ExportDirectory->NumberOfNames - 1;
501 while (High >= Low)
502 {
503 /* Get new middle value */
504 Mid = (Low + High) >> 1;
505
506 /* Compare name */
507 Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
508 if (Ret < 0)
509 {
510 /* Update high */
511 High = Mid - 1;
512 }
513 else if (Ret > 0)
514 {
515 /* Update low */
516 Low = Mid + 1;
517 }
518 else
519 {
520 /* We got it */
521 break;
522 }
523 }
524
525 /* Check if we couldn't find it */
526 if (High < Low) return NULL;
527
528 /* Otherwise, this is the ordinal */
529 Ordinal = OrdinalTable[Mid];
530
531 /* Validate the ordinal */
532 if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL;
533
534 /* Resolve the address and write it */
535 ExportTable = (PULONG)((ULONG_PTR)DllBase +
536 ExportDirectory->AddressOfFunctions);
537 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
538
539 /* We found it! */
540 ASSERT(!(Function > (PVOID)ExportDirectory) &&
541 (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
542 return Function;
543 }
544
545 VOID
546 NTAPI
547 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
548 IN BOOLEAN Insert)
549 {
550 KIRQL OldIrql;
551
552 /* Acquire module list lock */
553 KeEnterCriticalRegion();
554 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
555
556 /* Acquire the spinlock too as we will insert or remove the entry */
557 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
558
559 /* Insert or remove from the list */
560 Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
561 RemoveEntryList(&LdrEntry->InLoadOrderLinks);
562
563 /* Release locks */
564 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
565 ExReleaseResourceLite(&PsLoadedModuleResource);
566 KeLeaveCriticalRegion();
567 }
568
569 VOID
570 NTAPI
571 INIT_FUNCTION
572 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
573 IN PVOID OldBase,
574 IN PVOID NewBase,
575 IN ULONG Size)
576 {
577 ULONG_PTR OldBaseTop, Delta;
578 PLDR_DATA_TABLE_ENTRY LdrEntry;
579 PLIST_ENTRY NextEntry;
580 ULONG ImportSize;
581 //
582 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load,
583 // since a real version of Windows would fail at this point, but they seem
584 // busy implementing features such as "HotPatch" support in GCC 4.6 instead,
585 // a feature which isn't even used by Windows. Priorities, priorities...
586 // Please note that Microsoft WDK EULA and license prohibits using
587 // the information contained within it for the generation of "non-Windows"
588 // drivers, which is precisely what LD will generate, since an LD driver
589 // will not load on Windows.
590 //
591 #ifdef _WORKING_LINKER_
592 ULONG i;
593 #endif
594 PULONG_PTR ImageThunk;
595 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
596
597 /* Calculate the top and delta */
598 OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
599 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
600
601 /* Loop the loader block */
602 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
603 NextEntry != &LoaderBlock->LoadOrderListHead;
604 NextEntry = NextEntry->Flink)
605 {
606 /* Get the loader entry */
607 LdrEntry = CONTAINING_RECORD(NextEntry,
608 LDR_DATA_TABLE_ENTRY,
609 InLoadOrderLinks);
610 #ifdef _WORKING_LINKER_
611 /* Get the IAT */
612 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
613 TRUE,
614 IMAGE_DIRECTORY_ENTRY_IAT,
615 &ImportSize);
616 if (!ImageThunk) continue;
617
618 /* Make sure we have an IAT */
619 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
620 for (i = 0; i < ImportSize; i++, ImageThunk++)
621 {
622 /* Check if it's within this module */
623 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
624 {
625 /* Relocate it */
626 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
627 ImageThunk, *ImageThunk, *ImageThunk + Delta);
628 *ImageThunk += Delta;
629 }
630 }
631 #else
632 /* Get the import table */
633 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
634 TRUE,
635 IMAGE_DIRECTORY_ENTRY_IMPORT,
636 &ImportSize);
637 if (!ImportDescriptor) continue;
638
639 /* Make sure we have an IAT */
640 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
641 while ((ImportDescriptor->Name) &&
642 (ImportDescriptor->OriginalFirstThunk))
643 {
644 /* Get the image thunk */
645 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
646 ImportDescriptor->FirstThunk);
647 while (*ImageThunk)
648 {
649 /* Check if it's within this module */
650 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
651 {
652 /* Relocate it */
653 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
654 ImageThunk, *ImageThunk, *ImageThunk + Delta);
655 *ImageThunk += Delta;
656 }
657
658 /* Go to the next thunk */
659 ImageThunk++;
660 }
661
662 /* Go to the next import */
663 ImportDescriptor++;
664 }
665 #endif
666 }
667 }
668
669 NTSTATUS
670 NTAPI
671 MiSnapThunk(IN PVOID DllBase,
672 IN PVOID ImageBase,
673 IN PIMAGE_THUNK_DATA Name,
674 IN PIMAGE_THUNK_DATA Address,
675 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
676 IN ULONG ExportSize,
677 IN BOOLEAN SnapForwarder,
678 OUT PCHAR *MissingApi)
679 {
680 BOOLEAN IsOrdinal;
681 USHORT Ordinal;
682 PULONG NameTable;
683 PUSHORT OrdinalTable;
684 PIMAGE_IMPORT_BY_NAME NameImport;
685 USHORT Hint;
686 ULONG Low = 0, Mid = 0, High;
687 LONG Ret;
688 NTSTATUS Status;
689 PCHAR MissingForwarder;
690 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
691 PULONG ExportTable;
692 ANSI_STRING DllName;
693 UNICODE_STRING ForwarderName;
694 PLIST_ENTRY NextEntry;
695 PLDR_DATA_TABLE_ENTRY LdrEntry;
696 ULONG ForwardExportSize;
697 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
698 PIMAGE_IMPORT_BY_NAME ForwardName;
699 SIZE_T ForwardLength;
700 IMAGE_THUNK_DATA ForwardThunk;
701 PAGED_CODE();
702
703 /* Check if this is an ordinal */
704 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
705 if ((IsOrdinal) && !(SnapForwarder))
706 {
707 /* Get the ordinal number and set it as missing */
708 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
709 ExportDirectory->Base);
710 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
711 }
712 else
713 {
714 /* Get the VA if we don't have to snap */
715 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
716 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
717
718 /* Copy the procedure name */
719 RtlStringCbCopyA(*MissingApi,
720 MAXIMUM_FILENAME_LENGTH,
721 (PCHAR)&NameImport->Name[0]);
722
723 /* Setup name tables */
724 DPRINT("Import name: %s\n", NameImport->Name);
725 NameTable = (PULONG)((ULONG_PTR)DllBase +
726 ExportDirectory->AddressOfNames);
727 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
728 ExportDirectory->AddressOfNameOrdinals);
729
730 /* Get the hint and check if it's valid */
731 Hint = NameImport->Hint;
732 if ((Hint < ExportDirectory->NumberOfNames) &&
733 !(strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
734 {
735 /* We have a match, get the ordinal number from here */
736 Ordinal = OrdinalTable[Hint];
737 }
738 else
739 {
740 /* Do a binary search */
741 High = ExportDirectory->NumberOfNames - 1;
742 while (High >= Low)
743 {
744 /* Get new middle value */
745 Mid = (Low + High) >> 1;
746
747 /* Compare name */
748 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
749 if (Ret < 0)
750 {
751 /* Update high */
752 High = Mid - 1;
753 }
754 else if (Ret > 0)
755 {
756 /* Update low */
757 Low = Mid + 1;
758 }
759 else
760 {
761 /* We got it */
762 break;
763 }
764 }
765
766 /* Check if we couldn't find it */
767 if (High < Low)
768 {
769 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport->Name);
770 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
771 }
772
773 /* Otherwise, this is the ordinal */
774 Ordinal = OrdinalTable[Mid];
775 }
776 }
777
778 /* Check if the ordinal is invalid */
779 if (Ordinal >= ExportDirectory->NumberOfFunctions)
780 {
781 /* Fail */
782 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
783 }
784 else
785 {
786 /* In case the forwarder is missing */
787 MissingForwarder = NameBuffer;
788
789 /* Resolve the address and write it */
790 ExportTable = (PULONG)((ULONG_PTR)DllBase +
791 ExportDirectory->AddressOfFunctions);
792 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
793
794 /* Assume success from now on */
795 Status = STATUS_SUCCESS;
796
797 /* Check if the function is actually a forwarder */
798 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
799 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
800 {
801 /* Now assume failure in case the forwarder doesn't exist */
802 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
803
804 /* Build the forwarder name */
805 DllName.Buffer = (PCHAR)Address->u1.Function;
806 DllName.Length = (USHORT)(strchr(DllName.Buffer, '.') -
807 DllName.Buffer) +
808 sizeof(ANSI_NULL);
809 DllName.MaximumLength = DllName.Length;
810
811 /* Convert it */
812 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
813 &DllName,
814 TRUE)))
815 {
816 /* We failed, just return an error */
817 return Status;
818 }
819
820 /* Loop the module list */
821 NextEntry = PsLoadedModuleList.Flink;
822 while (NextEntry != &PsLoadedModuleList)
823 {
824 /* Get the loader entry */
825 LdrEntry = CONTAINING_RECORD(NextEntry,
826 LDR_DATA_TABLE_ENTRY,
827 InLoadOrderLinks);
828
829 /* Check if it matches */
830 if (RtlPrefixString((PSTRING)&ForwarderName,
831 (PSTRING)&LdrEntry->BaseDllName,
832 TRUE))
833 {
834 /* Get the forwarder export directory */
835 ForwardExportDirectory =
836 RtlImageDirectoryEntryToData(LdrEntry->DllBase,
837 TRUE,
838 IMAGE_DIRECTORY_ENTRY_EXPORT,
839 &ForwardExportSize);
840 if (!ForwardExportDirectory) break;
841
842 /* Allocate a name entry */
843 ForwardLength = strlen(DllName.Buffer + DllName.Length) +
844 sizeof(ANSI_NULL);
845 ForwardName = ExAllocatePoolWithTag(PagedPool,
846 sizeof(*ForwardName) +
847 ForwardLength,
848 TAG_LDR_WSTR);
849 if (!ForwardName) break;
850
851 /* Copy the data */
852 RtlCopyMemory(&ForwardName->Name[0],
853 DllName.Buffer + DllName.Length,
854 ForwardLength);
855 ForwardName->Hint = 0;
856
857 /* Set the new address */
858 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
859
860 /* Snap the forwarder */
861 Status = MiSnapThunk(LdrEntry->DllBase,
862 ImageBase,
863 &ForwardThunk,
864 &ForwardThunk,
865 ForwardExportDirectory,
866 ForwardExportSize,
867 TRUE,
868 &MissingForwarder);
869
870 /* Free the forwarder name and set the thunk */
871 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
872 Address->u1 = ForwardThunk.u1;
873 break;
874 }
875
876 /* Go to the next entry */
877 NextEntry = NextEntry->Flink;
878 }
879
880 /* Free the name */
881 RtlFreeUnicodeString(&ForwarderName);
882 }
883 }
884
885 /* Return status */
886 return Status;
887 }
888
889 NTSTATUS
890 NTAPI
891 MmUnloadSystemImage(IN PVOID ImageHandle)
892 {
893 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
894 PVOID BaseAddress = LdrEntry->DllBase;
895 NTSTATUS Status;
896 STRING TempName;
897 BOOLEAN HadEntry = FALSE;
898
899 /* Acquire the loader lock */
900 KeEnterCriticalRegion();
901 KeWaitForSingleObject(&MmSystemLoadLock,
902 WrVirtualMemory,
903 KernelMode,
904 FALSE,
905 NULL);
906
907 /* Check if this driver was loaded at boot and didn't get imports parsed */
908 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) goto Done;
909
910 /* We should still be alive */
911 ASSERT(LdrEntry->LoadCount != 0);
912 LdrEntry->LoadCount--;
913
914 /* Check if we're still loaded */
915 if (LdrEntry->LoadCount) goto Done;
916
917 /* We should cleanup... are symbols loaded */
918 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
919 {
920 /* Create the ANSI name */
921 Status = RtlUnicodeStringToAnsiString(&TempName,
922 &LdrEntry->BaseDllName,
923 TRUE);
924 if (NT_SUCCESS(Status))
925 {
926 /* Unload the symbols */
927 DbgUnLoadImageSymbols(&TempName,
928 BaseAddress,
929 (ULONG_PTR)ZwCurrentProcess());
930 RtlFreeAnsiString(&TempName);
931 }
932 }
933
934 /* FIXME: Free the driver */
935 DPRINT1("Leaking driver: %wZ\n", &LdrEntry->BaseDllName);
936 //MmFreeSection(LdrEntry->DllBase);
937
938 /* Check if we're linked in */
939 if (LdrEntry->InLoadOrderLinks.Flink)
940 {
941 /* Remove us */
942 MiProcessLoaderEntry(LdrEntry, FALSE);
943 HadEntry = TRUE;
944 }
945
946 /* Dereference and clear the imports */
947 MiDereferenceImports(LdrEntry->LoadedImports);
948 MiClearImports(LdrEntry);
949
950 /* Check if the entry needs to go away */
951 if (HadEntry)
952 {
953 /* Check if it had a name */
954 if (LdrEntry->FullDllName.Buffer)
955 {
956 /* Free it */
957 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR);
958 }
959
960 /* Check if we had a section */
961 if (LdrEntry->SectionPointer)
962 {
963 /* Dereference it */
964 ObDereferenceObject(LdrEntry->SectionPointer);
965 }
966
967 /* Free the entry */
968 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
969 }
970
971 /* Release the system lock and return */
972 Done:
973 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
974 KeLeaveCriticalRegion();
975 return STATUS_SUCCESS;
976 }
977
978 NTSTATUS
979 NTAPI
980 MiResolveImageReferences(IN PVOID ImageBase,
981 IN PUNICODE_STRING ImageFileDirectory,
982 IN PUNICODE_STRING NamePrefix OPTIONAL,
983 OUT PCHAR *MissingApi,
984 OUT PWCHAR *MissingDriver,
985 OUT PLOAD_IMPORTS *LoadImports)
986 {
987 PCHAR MissingApiBuffer = *MissingApi, ImportName;
988 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
989 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
990 PLOAD_IMPORTS LoadedImports, NewImports;
991 ULONG GdiLink, NormalLink, i;
992 BOOLEAN ReferenceNeeded, Loaded;
993 ANSI_STRING TempString;
994 UNICODE_STRING NameString, DllName;
995 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
996 PVOID ImportBase, DllBase;
997 PLIST_ENTRY NextEntry;
998 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
999 NTSTATUS Status;
1000 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
1001 PAGED_CODE();
1002 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
1003 __FUNCTION__, ImageBase, ImageFileDirectory);
1004
1005 /* Assume no imports */
1006 *LoadImports = MM_SYSLDR_NO_IMPORTS;
1007
1008 /* Get the import descriptor */
1009 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
1010 TRUE,
1011 IMAGE_DIRECTORY_ENTRY_IMPORT,
1012 &ImportSize);
1013 if (!ImportDescriptor) return STATUS_SUCCESS;
1014
1015 /* Loop all imports to count them */
1016 for (CurrentImport = ImportDescriptor;
1017 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
1018 CurrentImport++)
1019 {
1020 /* One more */
1021 ImportCount++;
1022 }
1023
1024 /* Make sure we have non-zero imports */
1025 if (ImportCount)
1026 {
1027 /* Calculate and allocate the list we'll need */
1028 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1029 LoadedImports = ExAllocatePoolWithTag(PagedPool,
1030 LoadedImportsSize,
1031 TAG_LDR_IMPORTS);
1032 if (LoadedImports)
1033 {
1034 /* Zero it */
1035 RtlZeroMemory(LoadedImports, LoadedImportsSize);
1036 LoadedImports->Count = ImportCount;
1037 }
1038 }
1039 else
1040 {
1041 /* No table */
1042 LoadedImports = NULL;
1043 }
1044
1045 /* Reset the import count and loop descriptors again */
1046 ImportCount = GdiLink = NormalLink = 0;
1047 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
1048 {
1049 /* Get the name */
1050 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
1051
1052 /* Check if this is a GDI driver */
1053 GdiLink = GdiLink |
1054 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
1055
1056 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/
1057 NormalLink = NormalLink |
1058 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
1059 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) &&
1060 (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) &&
1061 (_strnicmp(ImportName, "irt", sizeof("irt") - 1)));
1062
1063 /* Check if this is a valid GDI driver */
1064 if ((GdiLink) && (NormalLink))
1065 {
1066 /* It's not, it's importing stuff it shouldn't be! */
1067 MiDereferenceImports(LoadedImports);
1068 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1069 return STATUS_PROCEDURE_NOT_FOUND;
1070 }
1071
1072 /* Check for user-mode printer or video card drivers, which don't belong */
1073 if (!(_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) ||
1074 !(_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) ||
1075 !(_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) ||
1076 !(_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) ||
1077 !(_strnicmp(ImportName, "user32", sizeof("user32") - 1)) ||
1078 !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)))
1079 {
1080 /* This is not kernel code */
1081 MiDereferenceImports(LoadedImports);
1082 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1083 return STATUS_PROCEDURE_NOT_FOUND;
1084 }
1085
1086 /* Check if this is a "core" import, which doesn't get referenced */
1087 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1088 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
1089 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
1090 {
1091 /* Don't reference this */
1092 ReferenceNeeded = FALSE;
1093 }
1094 else
1095 {
1096 /* Reference these modules */
1097 ReferenceNeeded = TRUE;
1098 }
1099
1100 /* Now setup a unicode string for the import */
1101 RtlInitAnsiString(&TempString, ImportName);
1102 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
1103 if (!NT_SUCCESS(Status))
1104 {
1105 /* Failed */
1106 MiDereferenceImports(LoadedImports);
1107 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1108 return Status;
1109 }
1110
1111 /* We don't support name prefixes yet */
1112 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
1113
1114 /* Remember that we haven't loaded the import at this point */
1115 CheckDllState:
1116 Loaded = FALSE;
1117 ImportBase = NULL;
1118
1119 /* Loop the driver list */
1120 NextEntry = PsLoadedModuleList.Flink;
1121 while (NextEntry != &PsLoadedModuleList)
1122 {
1123 /* Get the loader entry and compare the name */
1124 LdrEntry = CONTAINING_RECORD(NextEntry,
1125 LDR_DATA_TABLE_ENTRY,
1126 InLoadOrderLinks);
1127 if (RtlEqualUnicodeString(&NameString,
1128 &LdrEntry->BaseDllName,
1129 TRUE))
1130 {
1131 /* Get the base address */
1132 ImportBase = LdrEntry->DllBase;
1133
1134 /* Check if we haven't loaded yet, and we need references */
1135 if (!(Loaded) && (ReferenceNeeded))
1136 {
1137 /* Make sure we're not already loading */
1138 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1139 {
1140 /* Increase the load count */
1141 LdrEntry->LoadCount++;
1142 }
1143 }
1144
1145 /* Done, break out */
1146 break;
1147 }
1148
1149 /* Go to the next entry */
1150 NextEntry = NextEntry->Flink;
1151 }
1152
1153 /* Check if we haven't loaded the import yet */
1154 if (!ImportBase)
1155 {
1156 /* Setup the import DLL name */
1157 DllName.MaximumLength = NameString.Length +
1158 ImageFileDirectory->Length +
1159 sizeof(UNICODE_NULL);
1160 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1161 DllName.MaximumLength,
1162 TAG_LDR_WSTR);
1163 if (DllName.Buffer)
1164 {
1165 /* Setup the base length and copy it */
1166 DllName.Length = ImageFileDirectory->Length;
1167 RtlCopyMemory(DllName.Buffer,
1168 ImageFileDirectory->Buffer,
1169 ImageFileDirectory->Length);
1170
1171 /* Now add the import name and null-terminate it */
1172 RtlAppendUnicodeStringToString(&DllName,
1173 &NameString);
1174 DllName.Buffer[DllName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1175
1176 /* Load the image */
1177 Status = MmLoadSystemImage(&DllName,
1178 NamePrefix,
1179 NULL,
1180 FALSE,
1181 (PVOID)&DllEntry,
1182 &DllBase);
1183 if (NT_SUCCESS(Status))
1184 {
1185 /* We can free the DLL Name */
1186 ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
1187 }
1188 else
1189 {
1190 /* Fill out the information for the error */
1191 *MissingDriver = DllName.Buffer;
1192 *(PULONG)MissingDriver |= 1;
1193 *MissingApi = NULL;
1194
1195 DPRINT1("Failed to load dependency: %wZ\n", &DllName);
1196 }
1197 }
1198 else
1199 {
1200 /* We're out of resources */
1201 Status = STATUS_INSUFFICIENT_RESOURCES;
1202 }
1203
1204 /* Check if we're OK until now */
1205 if (NT_SUCCESS(Status))
1206 {
1207 /* We're now loaded */
1208 Loaded = TRUE;
1209
1210 /* Sanity check */
1211 ASSERT(DllBase == DllEntry->DllBase);
1212
1213 /* Call the initialization routines */
1214 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
1215 if (!NT_SUCCESS(Status))
1216 {
1217 /* We failed, unload the image */
1218 MmUnloadSystemImage(DllEntry);
1219 DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status);
1220 while (TRUE);
1221 Loaded = FALSE;
1222 }
1223 }
1224
1225 /* Check if we failed by here */
1226 if (!NT_SUCCESS(Status))
1227 {
1228 /* Cleanup and return */
1229 RtlFreeUnicodeString(&NameString);
1230 MiDereferenceImports(LoadedImports);
1231 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1232 return Status;
1233 }
1234
1235 /* Loop again to make sure that everything is OK */
1236 goto CheckDllState;
1237 }
1238
1239 /* Check if we're support to reference this import */
1240 if ((ReferenceNeeded) && (LoadedImports))
1241 {
1242 /* Make sure we're not already loading */
1243 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1244 {
1245 /* Add the entry */
1246 LoadedImports->Entry[ImportCount] = LdrEntry;
1247 ImportCount++;
1248 }
1249 }
1250
1251 /* Free the import name */
1252 RtlFreeUnicodeString(&NameString);
1253
1254 /* Set the missing driver name and get the export directory */
1255 *MissingDriver = LdrEntry->BaseDllName.Buffer;
1256 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
1257 TRUE,
1258 IMAGE_DIRECTORY_ENTRY_EXPORT,
1259 &ExportSize);
1260 if (!ExportDirectory)
1261 {
1262 /* Cleanup and return */
1263 MiDereferenceImports(LoadedImports);
1264 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1265 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver);
1266 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
1267 }
1268
1269 /* Make sure we have an IAT */
1270 if (ImportDescriptor->OriginalFirstThunk)
1271 {
1272 /* Get the first thunks */
1273 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
1274 ImportDescriptor->OriginalFirstThunk);
1275 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
1276 ImportDescriptor->FirstThunk);
1277
1278 /* Loop the IAT */
1279 while (OrigThunk->u1.AddressOfData)
1280 {
1281 /* Snap thunk */
1282 Status = MiSnapThunk(ImportBase,
1283 ImageBase,
1284 OrigThunk++,
1285 FirstThunk++,
1286 ExportDirectory,
1287 ExportSize,
1288 FALSE,
1289 MissingApi);
1290 if (!NT_SUCCESS(Status))
1291 {
1292 /* Cleanup and return */
1293 MiDereferenceImports(LoadedImports);
1294 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1295 return Status;
1296 }
1297
1298 /* Reset the buffer */
1299 *MissingApi = MissingApiBuffer;
1300 }
1301 }
1302
1303 /* Go to the next import */
1304 ImportDescriptor++;
1305 }
1306
1307 /* Check if we have an import list */
1308 if (LoadedImports)
1309 {
1310 /* Reset the count again, and loop entries */
1311 ImportCount = 0;
1312 for (i = 0; i < LoadedImports->Count; i++)
1313 {
1314 if (LoadedImports->Entry[i])
1315 {
1316 /* Got an entry, OR it with 1 in case it's the single entry */
1317 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] |
1318 MM_SYSLDR_SINGLE_ENTRY);
1319 ImportCount++;
1320 }
1321 }
1322
1323 /* Check if we had no imports */
1324 if (!ImportCount)
1325 {
1326 /* Free the list and set it to no imports */
1327 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1328 LoadedImports = MM_SYSLDR_NO_IMPORTS;
1329 }
1330 else if (ImportCount == 1)
1331 {
1332 /* Just one entry, we can free the table and only use our entry */
1333 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1334 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
1335 }
1336 else if (ImportCount != LoadedImports->Count)
1337 {
1338 /* Allocate a new list */
1339 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1340 NewImports = ExAllocatePoolWithTag(PagedPool,
1341 LoadedImportsSize,
1342 TAG_LDR_IMPORTS);
1343 if (NewImports)
1344 {
1345 /* Set count */
1346 NewImports->Count = 0;
1347
1348 /* Loop all the imports */
1349 for (i = 0; i < LoadedImports->Count; i++)
1350 {
1351 /* Make sure it's valid */
1352 if (LoadedImports->Entry[i])
1353 {
1354 /* Copy it */
1355 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
1356 NewImports->Count++;
1357 }
1358 }
1359
1360 /* Free the old copy */
1361 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
1362 LoadedImports = NewImports;
1363 }
1364 }
1365
1366 /* Return the list */
1367 *LoadImports = LoadedImports;
1368 }
1369
1370 /* Return success */
1371 return STATUS_SUCCESS;
1372 }
1373
1374 VOID
1375 NTAPI
1376 MiFreeInitializationCode(IN PVOID InitStart,
1377 IN PVOID InitEnd)
1378 {
1379 PMMPTE PointerPte;
1380 PFN_NUMBER PagesFreed;
1381
1382 /* Get the start PTE */
1383 PointerPte = MiAddressToPte(InitStart);
1384 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart) == FALSE);
1385
1386 /* Compute the number of pages we expect to free */
1387 PagesFreed = (PFN_NUMBER)(MiAddressToPte(InitEnd) - PointerPte + 1);
1388
1389 /* Try to actually free them */
1390 PagesFreed = MiDeleteSystemPageableVm(PointerPte,
1391 PagesFreed,
1392 0,
1393 NULL);
1394 }
1395
1396 VOID
1397 NTAPI
1398 INIT_FUNCTION
1399 MiFindInitializationCode(OUT PVOID *StartVa,
1400 OUT PVOID *EndVa)
1401 {
1402 ULONG Size, SectionCount, Alignment;
1403 PLDR_DATA_TABLE_ENTRY LdrEntry;
1404 ULONG_PTR DllBase, InitStart, InitEnd, ImageEnd, InitCode;
1405 PLIST_ENTRY NextEntry;
1406 PIMAGE_NT_HEADERS NtHeader;
1407 PIMAGE_SECTION_HEADER Section, LastSection;
1408 BOOLEAN InitFound;
1409
1410 /* So we don't free our own code yet */
1411 InitCode = (ULONG_PTR)&MiFindInitializationCode;
1412
1413 /* Assume failure */
1414 *StartVa = NULL;
1415
1416 /* Enter a critical region while we loop the list */
1417 KeEnterCriticalRegion();
1418
1419 /* Loop all loaded modules */
1420 NextEntry = PsLoadedModuleList.Flink;
1421 while (NextEntry != &PsLoadedModuleList)
1422 {
1423 /* Get the loader entry and its DLL base */
1424 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1425 DllBase = (ULONG_PTR)LdrEntry->DllBase;
1426
1427 /* Get the NT header */
1428 NtHeader = RtlImageNtHeader((PVOID)DllBase);
1429 if (!NtHeader)
1430 {
1431 /* Keep going */
1432 NextEntry = NextEntry->Flink;
1433 continue;
1434 }
1435
1436 /* Get the first section, the section count, and scan them all */
1437 Section = IMAGE_FIRST_SECTION(NtHeader);
1438 SectionCount = NtHeader->FileHeader.NumberOfSections;
1439 InitStart = 0;
1440 while (SectionCount > 0)
1441 {
1442 /* Assume failure */
1443 InitFound = FALSE;
1444
1445 /* Is this the INIT section or a discardable section? */
1446 if ((*(PULONG)Section->Name == 'TINI') ||
1447 ((Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)))
1448 {
1449 /* Remember this */
1450 InitFound = TRUE;
1451 }
1452
1453 if (InitFound)
1454 {
1455 /* Pick the biggest size -- either raw or virtual */
1456 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
1457
1458 /* Read the section alignment */
1459 Alignment = NtHeader->OptionalHeader.SectionAlignment;
1460
1461 /* Align the start and end addresses appropriately */
1462 InitStart = DllBase + Section->VirtualAddress;
1463 InitEnd = ((Alignment + InitStart + Size - 2) & 0xFFFFF000) - 1;
1464 InitStart = (InitStart + (PAGE_SIZE - 1)) & 0xFFFFF000;
1465
1466 /* Have we reached the last section? */
1467 if (SectionCount == 1)
1468 {
1469 /* Remember this */
1470 LastSection = Section;
1471 }
1472 else
1473 {
1474 /* We have not, loop all the sections */
1475 LastSection = NULL;
1476 do
1477 {
1478 /* Keep going until we find a non-discardable section range */
1479 SectionCount--;
1480 Section++;
1481 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
1482 {
1483 /* Discardable, so record it, then keep going */
1484 LastSection = Section;
1485 }
1486 else
1487 {
1488 /* Non-contigous discard flag, or no flag, break out */
1489 break;
1490 }
1491 }
1492 while (SectionCount > 1);
1493 }
1494
1495 /* Have we found a discardable or init section? */
1496 if (LastSection)
1497 {
1498 /* Pick the biggest size -- either raw or virtual */
1499 Size = max(LastSection->SizeOfRawData, LastSection->Misc.VirtualSize);
1500
1501 /* Use this as the end of the section address */
1502 InitEnd = DllBase + LastSection->VirtualAddress + Size - 1;
1503
1504 /* Have we reached the last section yet? */
1505 if (SectionCount != 1)
1506 {
1507 /* Then align this accross the session boundary */
1508 InitEnd = ((Alignment + InitEnd - 1) & 0XFFFFF000) - 1;
1509 }
1510 }
1511
1512 /* Make sure we don't let the init section go past the image */
1513 ImageEnd = DllBase + LdrEntry->SizeOfImage;
1514 if (InitEnd > ImageEnd) InitEnd = (ImageEnd - 1) | (PAGE_SIZE - 1);
1515
1516 /* Make sure we have a valid, non-zero init section */
1517 if (InitStart <= InitEnd)
1518 {
1519 /* Make sure we are not within this code itself */
1520 if ((InitCode >= InitStart) && (InitCode <= InitEnd))
1521 {
1522 /* Return it, we can't free ourselves now */
1523 ASSERT(*StartVa == 0);
1524 *StartVa = (PVOID)InitStart;
1525 *EndVa = (PVOID)InitEnd;
1526 }
1527 else
1528 {
1529 /* This isn't us -- go ahead and free it */
1530 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID)InitStart) == FALSE);
1531 MiFreeInitializationCode((PVOID)InitStart, (PVOID)InitEnd);
1532 }
1533 }
1534 }
1535
1536 /* Move to the next section */
1537 SectionCount--;
1538 Section++;
1539 }
1540
1541 /* Move to the next module */
1542 NextEntry = NextEntry->Flink;
1543 }
1544
1545 /* Leave the critical region and return */
1546 KeLeaveCriticalRegion();
1547 }
1548
1549 /*
1550 * Note: This function assumes that all discardable sections are at the end of
1551 * the PE file. It searches backwards until it finds the non-discardable section
1552 */
1553 VOID
1554 NTAPI
1555 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
1556 {
1557 PMMPTE StartPte, EndPte;
1558 PFN_NUMBER PageCount;
1559 PVOID DllBase;
1560 ULONG i;
1561 PIMAGE_NT_HEADERS NtHeader;
1562 PIMAGE_SECTION_HEADER Section, DiscardSection;
1563 ULONG PagesDeleted;
1564
1565 /* Get the base address and the page count */
1566 DllBase = LdrEntry->DllBase;
1567 PageCount = LdrEntry->SizeOfImage >> PAGE_SHIFT;
1568
1569 /* Get the last PTE in this image */
1570 EndPte = MiAddressToPte(DllBase) + PageCount;
1571
1572 /* Get the NT header */
1573 NtHeader = RtlImageNtHeader(DllBase);
1574 if (!NtHeader) return;
1575
1576 /* Get the last section and loop each section backwards */
1577 Section = IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections;
1578 DiscardSection = NULL;
1579 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
1580 {
1581 /* Go back a section and check if it's discardable */
1582 Section--;
1583 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
1584 {
1585 /* It is, select it for freeing */
1586 DiscardSection = Section;
1587 }
1588 else
1589 {
1590 /* No more discardable sections exist, bail out */
1591 break;
1592 }
1593 }
1594
1595 /* Bail out if there's nothing to free */
1596 if (!DiscardSection) return;
1597
1598 /* Push the DLL base to the first disacrable section, and get its PTE */
1599 DllBase = (PVOID)ROUND_TO_PAGES((ULONG_PTR)DllBase + DiscardSection->VirtualAddress);
1600 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase) == FALSE);
1601 StartPte = MiAddressToPte(DllBase);
1602
1603 /* Check how many pages to free total */
1604 PageCount = (PFN_NUMBER)(EndPte - StartPte);
1605 if (!PageCount) return;
1606
1607 /* Delete this many PTEs */
1608 PagesDeleted = MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
1609 }
1610
1611 VOID
1612 NTAPI
1613 INIT_FUNCTION
1614 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1615 {
1616 PLIST_ENTRY NextEntry;
1617 ULONG i = 0;
1618 PIMAGE_NT_HEADERS NtHeader;
1619 PLDR_DATA_TABLE_ENTRY LdrEntry;
1620 PIMAGE_FILE_HEADER FileHeader;
1621 BOOLEAN ValidRelocs;
1622 PIMAGE_DATA_DIRECTORY DataDirectory;
1623 PVOID DllBase, NewImageAddress;
1624 NTSTATUS Status;
1625 PMMPTE PointerPte, StartPte, LastPte;
1626 PFN_COUNT PteCount;
1627 PMMPFN Pfn1;
1628 MMPTE TempPte, OldPte;
1629
1630 /* Loop driver list */
1631 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1632 NextEntry != &LoaderBlock->LoadOrderListHead;
1633 NextEntry = NextEntry->Flink)
1634 {
1635 /* Get the loader entry and NT header */
1636 LdrEntry = CONTAINING_RECORD(NextEntry,
1637 LDR_DATA_TABLE_ENTRY,
1638 InLoadOrderLinks);
1639 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1640
1641 /* Debug info */
1642 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1643 LdrEntry->DllBase,
1644 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
1645 &LdrEntry->FullDllName);
1646
1647 /* Get the first PTE and the number of PTEs we'll need */
1648 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
1649 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
1650 LastPte = StartPte + PteCount;
1651
1652 #if MI_TRACE_PFNS
1653 /* Loop the PTEs */
1654 while (PointerPte < LastPte)
1655 {
1656 ULONG len;
1657 ASSERT(PointerPte->u.Hard.Valid == 1);
1658 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1659 len = wcslen(LdrEntry->BaseDllName.Buffer) * sizeof(WCHAR);
1660 snprintf(Pfn1->ProcessName, min(16, len), "%S", LdrEntry->BaseDllName.Buffer);
1661 PointerPte++;
1662 }
1663 #endif
1664 /* Skip kernel and HAL */
1665 /* ROS HACK: Skip BOOTVID/KDCOM too */
1666 i++;
1667 if (i <= 4) continue;
1668
1669 /* Skip non-drivers */
1670 if (!NtHeader) continue;
1671
1672 /* Get the file header and make sure we can relocate */
1673 FileHeader = &NtHeader->FileHeader;
1674 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1675 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1676 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1677
1678 /* Everything made sense until now, check the relocation section too */
1679 DataDirectory = &NtHeader->OptionalHeader.
1680 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1681 if (!DataDirectory->VirtualAddress)
1682 {
1683 /* We don't really have relocations */
1684 ValidRelocs = FALSE;
1685 }
1686 else
1687 {
1688 /* Make sure the size is valid */
1689 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1690 LdrEntry->SizeOfImage)
1691 {
1692 /* They're not, skip */
1693 continue;
1694 }
1695
1696 /* We have relocations */
1697 ValidRelocs = TRUE;
1698 }
1699
1700 /* Remember the original address */
1701 DllBase = LdrEntry->DllBase;
1702
1703 /* Loop the PTEs */
1704 PointerPte = StartPte;
1705 while (PointerPte < LastPte)
1706 {
1707 /* Mark the page modified in the PFN database */
1708 ASSERT(PointerPte->u.Hard.Valid == 1);
1709 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1710 ASSERT(Pfn1->u3.e1.Rom == 0);
1711 Pfn1->u3.e1.Modified = TRUE;
1712
1713 /* Next */
1714 PointerPte++;
1715 }
1716
1717 /* Now reserve system PTEs for the image */
1718 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
1719 if (!PointerPte)
1720 {
1721 /* Shouldn't happen */
1722 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1723 while (TRUE);
1724 }
1725
1726 /* This is the new virtual address for the module */
1727 LastPte = PointerPte + PteCount;
1728 NewImageAddress = MiPteToAddress(PointerPte);
1729
1730 /* Sanity check */
1731 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1732 ASSERT(ExpInitializationPhase == 0);
1733
1734 /* Loop the new driver PTEs */
1735 TempPte = ValidKernelPte;
1736 while (PointerPte < LastPte)
1737 {
1738 /* Copy the old data */
1739 OldPte = *StartPte;
1740 ASSERT(OldPte.u.Hard.Valid == 1);
1741
1742 /* Set page number from the loader's memory */
1743 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
1744
1745 /* Write it */
1746 MI_WRITE_VALID_PTE(PointerPte, TempPte);
1747
1748 /* Move on */
1749 PointerPte++;
1750 StartPte++;
1751 }
1752
1753 /* Update position */
1754 PointerPte -= PteCount;
1755
1756 /* Sanity check */
1757 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1758
1759 /* Set the image base to the address where the loader put it */
1760 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1761
1762 /* Check if we had relocations */
1763 if (ValidRelocs)
1764 {
1765 /* Relocate the image */
1766 Status = LdrRelocateImageWithBias(NewImageAddress,
1767 0,
1768 "SYSLDR",
1769 STATUS_SUCCESS,
1770 STATUS_CONFLICTING_ADDRESSES,
1771 STATUS_INVALID_IMAGE_FORMAT);
1772 if (!NT_SUCCESS(Status))
1773 {
1774 /* This shouldn't happen */
1775 DPRINT1("Relocations failed!\n");
1776 while (TRUE);
1777 }
1778 }
1779
1780 /* Update the loader entry */
1781 LdrEntry->DllBase = NewImageAddress;
1782
1783 /* Update the thunks */
1784 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1785 MiUpdateThunks(LoaderBlock,
1786 DllBase,
1787 NewImageAddress,
1788 LdrEntry->SizeOfImage);
1789
1790 /* Update the loader entry */
1791 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
1792 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1793 NtHeader->OptionalHeader.AddressOfEntryPoint);
1794 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
1795
1796 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1797 }
1798 }
1799
1800 NTSTATUS
1801 NTAPI
1802 INIT_FUNCTION
1803 MiBuildImportsForBootDrivers(VOID)
1804 {
1805 PLIST_ENTRY NextEntry, NextEntry2;
1806 PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry;
1807 PLDR_DATA_TABLE_ENTRY* EntryArray;
1808 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
1809 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
1810 PLOAD_IMPORTS LoadedImports;
1811 ULONG LoadedImportsSize, ImportSize;
1812 PULONG_PTR ImageThunk;
1813 ULONG_PTR DllBase, DllEnd;
1814 ULONG Modules = 0, i, j = 0;
1815 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
1816
1817 /* Initialize variables */
1818 KernelEntry = HalEntry = LastEntry = NULL;
1819
1820 /* Loop the loaded module list... we are early enough that no lock is needed */
1821 NextEntry = PsLoadedModuleList.Flink;
1822 while (NextEntry != &PsLoadedModuleList)
1823 {
1824 /* Get the entry */
1825 LdrEntry = CONTAINING_RECORD(NextEntry,
1826 LDR_DATA_TABLE_ENTRY,
1827 InLoadOrderLinks);
1828
1829 /* Check if it's the kernel or HAL */
1830 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
1831 {
1832 /* Found it */
1833 KernelEntry = LdrEntry;
1834 }
1835 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
1836 {
1837 /* Found it */
1838 HalEntry = LdrEntry;
1839 }
1840
1841 /* Check if this is a driver DLL */
1842 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1843 {
1844 /* Check if this is the HAL or kernel */
1845 if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry))
1846 {
1847 /* Add a reference */
1848 LdrEntry->LoadCount = 1;
1849 }
1850 else
1851 {
1852 /* No referencing needed */
1853 LdrEntry->LoadCount = 0;
1854 }
1855 }
1856 else
1857 {
1858 /* No referencing needed */
1859 LdrEntry->LoadCount = 0;
1860 }
1861
1862 /* Remember this came from the loader */
1863 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
1864
1865 /* Keep looping */
1866 NextEntry = NextEntry->Flink;
1867 Modules++;
1868 }
1869
1870 /* We must have at least found the kernel and HAL */
1871 if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND;
1872
1873 /* Allocate the list */
1874 EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), TAG_LDR_IMPORTS);
1875 if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES;
1876
1877 /* Loop the loaded module list again */
1878 NextEntry = PsLoadedModuleList.Flink;
1879 while (NextEntry != &PsLoadedModuleList)
1880 {
1881 /* Get the entry */
1882 LdrEntry = CONTAINING_RECORD(NextEntry,
1883 LDR_DATA_TABLE_ENTRY,
1884 InLoadOrderLinks);
1885 #ifdef _WORKING_LOADER_
1886 /* Get its imports */
1887 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1888 TRUE,
1889 IMAGE_DIRECTORY_ENTRY_IAT,
1890 &ImportSize);
1891 if (!ImageThunk)
1892 #else
1893 /* Get its imports */
1894 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1895 TRUE,
1896 IMAGE_DIRECTORY_ENTRY_IMPORT,
1897 &ImportSize);
1898 if (!ImportDescriptor)
1899 #endif
1900 {
1901 /* None present */
1902 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
1903 NextEntry = NextEntry->Flink;
1904 continue;
1905 }
1906
1907 /* Clear the list and count the number of IAT thunks */
1908 RtlZeroMemory(EntryArray, Modules * sizeof(PVOID));
1909 #ifdef _WORKING_LOADER_
1910 ImportSize /= sizeof(ULONG_PTR);
1911
1912 /* Scan the thunks */
1913 for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++)
1914 #else
1915 DllBase = DllEnd = i = 0;
1916 while ((ImportDescriptor->Name) &&
1917 (ImportDescriptor->OriginalFirstThunk))
1918 {
1919 /* Get the image thunk */
1920 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
1921 ImportDescriptor->FirstThunk);
1922 while (*ImageThunk)
1923 #endif
1924 {
1925 /* Do we already have an address? */
1926 if (DllBase)
1927 {
1928 /* Is the thunk in the same address? */
1929 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
1930 {
1931 /* Skip it, we already have a reference for it */
1932 ASSERT(EntryArray[j]);
1933 ImageThunk++;
1934 continue;
1935 }
1936 }
1937
1938 /* Loop the loaded module list to locate this address owner */
1939 j = 0;
1940 NextEntry2 = PsLoadedModuleList.Flink;
1941 while (NextEntry2 != &PsLoadedModuleList)
1942 {
1943 /* Get the entry */
1944 LdrEntry2 = CONTAINING_RECORD(NextEntry2,
1945 LDR_DATA_TABLE_ENTRY,
1946 InLoadOrderLinks);
1947
1948 /* Get the address range for this module */
1949 DllBase = (ULONG_PTR)LdrEntry2->DllBase;
1950 DllEnd = DllBase + LdrEntry2->SizeOfImage;
1951
1952 /* Check if this IAT entry matches it */
1953 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
1954 {
1955 /* Save it */
1956 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
1957 EntryArray[j] = LdrEntry2;
1958 break;
1959 }
1960
1961 /* Keep searching */
1962 NextEntry2 = NextEntry2->Flink;
1963 j++;
1964 }
1965
1966 /* Do we have a thunk outside the range? */
1967 if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd))
1968 {
1969 /* Could be 0... */
1970 if (*ImageThunk)
1971 {
1972 /* Should not be happening */
1973 DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
1974 LdrEntry, ImageThunk, *ImageThunk);
1975 ASSERT(FALSE);
1976 }
1977
1978 /* Reset if we hit this */
1979 DllBase = 0;
1980 }
1981 #ifndef _WORKING_LOADER_
1982 ImageThunk++;
1983 }
1984
1985 i++;
1986 ImportDescriptor++;
1987 #endif
1988 }
1989
1990 /* Now scan how many imports we really have */
1991 for (i = 0, ImportSize = 0; i < Modules; i++)
1992 {
1993 /* Skip HAL and kernel */
1994 if ((EntryArray[i]) &&
1995 (EntryArray[i] != HalEntry) &&
1996 (EntryArray[i] != KernelEntry))
1997 {
1998 /* A valid reference */
1999 LastEntry = EntryArray[i];
2000 ImportSize++;
2001 }
2002 }
2003
2004 /* Do we have any imports after all? */
2005 if (!ImportSize)
2006 {
2007 /* No */
2008 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
2009 }
2010 else if (ImportSize == 1)
2011 {
2012 /* A single entry import */
2013 LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY);
2014 LastEntry->LoadCount++;
2015 }
2016 else
2017 {
2018 /* We need an import table */
2019 LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T);
2020 LoadedImports = ExAllocatePoolWithTag(PagedPool,
2021 LoadedImportsSize,
2022 TAG_LDR_IMPORTS);
2023 ASSERT(LoadedImports);
2024
2025 /* Save the count */
2026 LoadedImports->Count = ImportSize;
2027
2028 /* Now copy all imports */
2029 for (i = 0, j = 0; i < Modules; i++)
2030 {
2031 /* Skip HAL and kernel */
2032 if ((EntryArray[i]) &&
2033 (EntryArray[i] != HalEntry) &&
2034 (EntryArray[i] != KernelEntry))
2035 {
2036 /* A valid reference */
2037 //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
2038 LoadedImports->Entry[j] = EntryArray[i];
2039 EntryArray[i]->LoadCount++;
2040 j++;
2041 }
2042 }
2043
2044 /* Should had as many entries as we expected */
2045 ASSERT(j == ImportSize);
2046 LdrEntry->LoadedImports = LoadedImports;
2047 }
2048
2049 /* Next */
2050 NextEntry = NextEntry->Flink;
2051 }
2052
2053 /* Free the initial array */
2054 ExFreePoolWithTag(EntryArray, TAG_LDR_IMPORTS);
2055
2056 /* FIXME: Might not need to keep the HAL/Kernel imports around */
2057
2058 /* Kernel and HAL are loaded at boot */
2059 KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
2060 HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
2061
2062 /* All worked well */
2063 return STATUS_SUCCESS;
2064 }
2065
2066 VOID
2067 NTAPI
2068 INIT_FUNCTION
2069 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
2070 {
2071 ULONG_PTR DllBase;
2072 PIMAGE_NT_HEADERS NtHeaders;
2073 PIMAGE_SECTION_HEADER SectionHeader;
2074 ULONG Sections, Size;
2075
2076 /* Get the kernel section header */
2077 DllBase = (ULONG_PTR)LdrEntry->DllBase;
2078 NtHeaders = RtlImageNtHeader((PVOID)DllBase);
2079 SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
2080
2081 /* Loop all the sections */
2082 Sections = NtHeaders->FileHeader.NumberOfSections;
2083 while (Sections)
2084 {
2085 /* Grab the size of the section */
2086 Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize);
2087
2088 /* Check for .RSRC section */
2089 if (*(PULONG)SectionHeader->Name == 'rsr.')
2090 {
2091 /* Remember the PTEs so we can modify them later */
2092 MiKernelResourceStartPte = MiAddressToPte(DllBase +
2093 SectionHeader->VirtualAddress);
2094 MiKernelResourceEndPte = MiKernelResourceStartPte +
2095 BYTES_TO_PAGES(SectionHeader->VirtualAddress + Size);
2096 }
2097 else if (*(PULONG)SectionHeader->Name == 'LOOP')
2098 {
2099 /* POOLCODE vs. POOLMI */
2100 if (*(PULONG)&SectionHeader->Name[4] == 'EDOC')
2101 {
2102 /* Found Ex* Pool code */
2103 ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
2104 ExPoolCodeEnd = ExPoolCodeStart + Size;
2105 }
2106 else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI')
2107 {
2108 /* Found Mm* Pool code */
2109 MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
2110 MmPoolCodeEnd = ExPoolCodeStart + Size;
2111 }
2112 }
2113 else if ((*(PULONG)SectionHeader->Name == 'YSIM') &&
2114 (*(PULONG)&SectionHeader->Name[4] == 'ETPS'))
2115 {
2116 /* Found MISYSPTE (Mm System PTE code)*/
2117 MmPteCodeStart = DllBase + SectionHeader->VirtualAddress;
2118 MmPteCodeEnd = ExPoolCodeStart + Size;
2119 }
2120
2121 /* Keep going */
2122 Sections--;
2123 SectionHeader++;
2124 }
2125 }
2126
2127 BOOLEAN
2128 NTAPI
2129 INIT_FUNCTION
2130 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
2131 {
2132 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
2133 PLIST_ENTRY ListHead, NextEntry;
2134 ULONG EntrySize;
2135
2136 /* Setup the loaded module list and locks */
2137 ExInitializeResourceLite(&PsLoadedModuleResource);
2138 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
2139 InitializeListHead(&PsLoadedModuleList);
2140
2141 /* Get loop variables and the kernel entry */
2142 ListHead = &LoaderBlock->LoadOrderListHead;
2143 NextEntry = ListHead->Flink;
2144 LdrEntry = CONTAINING_RECORD(NextEntry,
2145 LDR_DATA_TABLE_ENTRY,
2146 InLoadOrderLinks);
2147 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
2148
2149 /* Locate resource section, pool code, and system pte code */
2150 MiLocateKernelSections(LdrEntry);
2151
2152 /* Loop the loader block */
2153 while (NextEntry != ListHead)
2154 {
2155 /* Get the loader entry */
2156 LdrEntry = CONTAINING_RECORD(NextEntry,
2157 LDR_DATA_TABLE_ENTRY,
2158 InLoadOrderLinks);
2159
2160 /* FIXME: ROS HACK. Make sure this is a driver */
2161 if (!RtlImageNtHeader(LdrEntry->DllBase))
2162 {
2163 /* Skip this entry */
2164 NextEntry = NextEntry->Flink;
2165 continue;
2166 }
2167
2168 /* Calculate the size we'll need and allocate a copy */
2169 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
2170 LdrEntry->BaseDllName.MaximumLength +
2171 sizeof(UNICODE_NULL);
2172 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
2173 if (!NewEntry) return FALSE;
2174
2175 /* Copy the entry over */
2176 *NewEntry = *LdrEntry;
2177
2178 /* Allocate the name */
2179 NewEntry->FullDllName.Buffer =
2180 ExAllocatePoolWithTag(PagedPool,
2181 LdrEntry->FullDllName.MaximumLength +
2182 sizeof(UNICODE_NULL),
2183 TAG_LDR_WSTR);
2184 if (!NewEntry->FullDllName.Buffer)
2185 {
2186 ExFreePoolWithTag(NewEntry, TAG_MODULE_OBJECT);
2187 return FALSE;
2188 }
2189
2190 /* Set the base name */
2191 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
2192
2193 /* Copy the full and base name */
2194 RtlCopyMemory(NewEntry->FullDllName.Buffer,
2195 LdrEntry->FullDllName.Buffer,
2196 LdrEntry->FullDllName.MaximumLength);
2197 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
2198 LdrEntry->BaseDllName.Buffer,
2199 LdrEntry->BaseDllName.MaximumLength);
2200
2201 /* Null-terminate the base name */
2202 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
2203 sizeof(WCHAR)] = UNICODE_NULL;
2204
2205 /* Insert the entry into the list */
2206 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
2207 NextEntry = NextEntry->Flink;
2208 }
2209
2210 /* Build the import lists for the boot drivers */
2211 MiBuildImportsForBootDrivers();
2212
2213 /* We're done */
2214 return TRUE;
2215 }
2216
2217 LOGICAL
2218 NTAPI
2219 MiUseLargeDriverPage(IN ULONG NumberOfPtes,
2220 IN OUT PVOID *ImageBaseAddress,
2221 IN PUNICODE_STRING BaseImageName,
2222 IN BOOLEAN BootDriver)
2223 {
2224 PLIST_ENTRY NextEntry;
2225 BOOLEAN DriverFound = FALSE;
2226 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry;
2227 ASSERT(KeGetCurrentIrql () <= APC_LEVEL);
2228 ASSERT(*ImageBaseAddress >= MmSystemRangeStart);
2229
2230 #ifdef _X86_
2231 if (!(KeFeatureBits & KF_LARGE_PAGE)) return FALSE;
2232 if (!(__readcr4() & CR4_PSE)) return FALSE;
2233 #endif
2234
2235 /* Make sure there's enough system PTEs for a large page driver */
2236 if (MmTotalFreeSystemPtes[SystemPteSpace] < (16 * (PDE_MAPPED_VA >> PAGE_SHIFT)))
2237 {
2238 return FALSE;
2239 }
2240
2241 /* This happens if the registry key had a "*" (wildcard) in it */
2242 if (MiLargePageAllDrivers == 0)
2243 {
2244 /* It didn't, so scan the list */
2245 NextEntry = MiLargePageDriverList.Flink;
2246 while (NextEntry != &MiLargePageDriverList)
2247 {
2248 /* Check if the driver name matches */
2249 LargePageDriverEntry = CONTAINING_RECORD(NextEntry,
2250 MI_LARGE_PAGE_DRIVER_ENTRY,
2251 Links);
2252 if (RtlEqualUnicodeString(BaseImageName,
2253 &LargePageDriverEntry->BaseName,
2254 TRUE))
2255 {
2256 /* Enable large pages for this driver */
2257 DriverFound = TRUE;
2258 break;
2259 }
2260
2261 /* Keep trying */
2262 NextEntry = NextEntry->Flink;
2263 }
2264
2265 /* If we didn't find the driver, it doesn't need large pages */
2266 if (DriverFound == FALSE) return FALSE;
2267 }
2268
2269 /* Nothing to do yet */
2270 DPRINT1("Large pages not supported!\n");
2271 return FALSE;
2272 }
2273
2274 ULONG
2275 NTAPI
2276 MiComputeDriverProtection(IN BOOLEAN SessionSpace,
2277 IN ULONG SectionProtection)
2278 {
2279 ULONG Protection = MM_ZERO_ACCESS;
2280
2281 /* Check if the caller gave anything */
2282 if (SectionProtection)
2283 {
2284 /* Always turn on execute access */
2285 SectionProtection |= IMAGE_SCN_MEM_EXECUTE;
2286
2287 /* Check if the registry setting is on or not */
2288 if (!MmEnforceWriteProtection)
2289 {
2290 /* Turn on write access too */
2291 SectionProtection |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE);
2292 }
2293 }
2294
2295 /* Convert to internal PTE flags */
2296 if (SectionProtection & IMAGE_SCN_MEM_EXECUTE) Protection |= MM_EXECUTE;
2297 if (SectionProtection & IMAGE_SCN_MEM_READ) Protection |= MM_READONLY;
2298
2299 /* Check for write access */
2300 if (SectionProtection & IMAGE_SCN_MEM_WRITE)
2301 {
2302 /* Session space is not supported */
2303 if (SessionSpace)
2304 {
2305 DPRINT1("Session drivers not supported\n");
2306 ASSERT(SessionSpace == FALSE);
2307 }
2308 else
2309 {
2310 /* Convert to internal PTE flag */
2311 Protection = (Protection & MM_EXECUTE) ? MM_EXECUTE_READWRITE : MM_READWRITE;
2312 }
2313 }
2314
2315 /* If there's no access at all by now, convert to internal no access flag */
2316 if (Protection == MM_ZERO_ACCESS) Protection = MM_NOACCESS;
2317
2318 /* Return the computed PTE protection */
2319 return Protection;
2320 }
2321
2322 VOID
2323 NTAPI
2324 MiSetSystemCodeProtection(IN PMMPTE FirstPte,
2325 IN PMMPTE LastPte,
2326 IN ULONG ProtectionMask)
2327 {
2328 /* I'm afraid to introduce regressions at the moment... */
2329 return;
2330 }
2331
2332 VOID
2333 NTAPI
2334 MiWriteProtectSystemImage(IN PVOID ImageBase)
2335 {
2336 PIMAGE_NT_HEADERS NtHeaders;
2337 PIMAGE_SECTION_HEADER Section;
2338 PFN_NUMBER DriverPages;
2339 ULONG CurrentProtection, SectionProtection, CombinedProtection = 0, ProtectionMask;
2340 ULONG Sections, Size;
2341 ULONG_PTR BaseAddress, CurrentAddress;
2342 PMMPTE PointerPte, StartPte, LastPte, CurrentPte, ComboPte = NULL;
2343 ULONG CurrentMask, CombinedMask = 0;
2344 PAGED_CODE();
2345
2346 /* No need to write protect physical memory-backed drivers (large pages) */
2347 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
2348
2349 /* Get the image headers */
2350 NtHeaders = RtlImageNtHeader(ImageBase);
2351 if (!NtHeaders) return;
2352
2353 /* Check if this is a session driver or not */
2354 if (!MI_IS_SESSION_ADDRESS(ImageBase))
2355 {
2356 /* Don't touch NT4 drivers */
2357 if (NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) return;
2358 if (NtHeaders->OptionalHeader.MajorImageVersion < 5) return;
2359 }
2360 else
2361 {
2362 /* Not supported */
2363 DPRINT1("Session drivers not supported\n");
2364 ASSERT(FALSE);
2365 }
2366
2367 /* These are the only protection masks we care about */
2368 ProtectionMask = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
2369
2370 /* Calculate the number of pages this driver is occupying */
2371 DriverPages = BYTES_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage);
2372
2373 /* Get the number of sections and the first section header */
2374 Sections = NtHeaders->FileHeader.NumberOfSections;
2375 ASSERT(Sections != 0);
2376 Section = IMAGE_FIRST_SECTION(NtHeaders);
2377
2378 /* Loop all the sections */
2379 CurrentAddress = (ULONG_PTR)ImageBase;
2380 while (Sections)
2381 {
2382 /* Get the section size */
2383 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
2384
2385 /* Get its virtual address */
2386 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
2387 if (BaseAddress < CurrentAddress)
2388 {
2389 /* Windows doesn't like these */
2390 DPRINT1("Badly linked image!\n");
2391 return;
2392 }
2393
2394 /* Remember the current address */
2395 CurrentAddress = BaseAddress + Size - 1;
2396
2397 /* Next */
2398 Sections--;
2399 Section++;
2400 }
2401
2402 /* Get the number of sections and the first section header */
2403 Sections = NtHeaders->FileHeader.NumberOfSections;
2404 ASSERT(Sections != 0);
2405 Section = IMAGE_FIRST_SECTION(NtHeaders);
2406
2407 /* Set the address at the end to initialize the loop */
2408 CurrentAddress = (ULONG_PTR)Section + Sections - 1;
2409 CurrentProtection = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
2410
2411 /* Set the PTE points for the image, and loop its sections */
2412 StartPte = MiAddressToPte(ImageBase);
2413 LastPte = StartPte + DriverPages;
2414 while (Sections)
2415 {
2416 /* Get the section size */
2417 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
2418
2419 /* Get its virtual address and PTE */
2420 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
2421 PointerPte = MiAddressToPte(BaseAddress);
2422
2423 /* Check if we were already protecting a run, and found a new run */
2424 if ((ComboPte) && (PointerPte > ComboPte))
2425 {
2426 /* Compute protection */
2427 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
2428
2429 /* Set it */
2430 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
2431
2432 /* Check for overlap */
2433 if (ComboPte == StartPte) StartPte++;
2434
2435 /* One done, reset variables */
2436 ComboPte = NULL;
2437 CombinedProtection = 0;
2438 }
2439
2440 /* Break out when needed */
2441 if (PointerPte >= LastPte) break;
2442
2443 /* Get the requested protection from the image header */
2444 SectionProtection = Section->Characteristics & ProtectionMask;
2445 if (SectionProtection == CurrentProtection)
2446 {
2447 /* Same protection, so merge the request */
2448 CurrentAddress = BaseAddress + Size - 1;
2449
2450 /* Next */
2451 Sections--;
2452 Section++;
2453 continue;
2454 }
2455
2456 /* This is now a new section, so close up the old one */
2457 CurrentPte = MiAddressToPte(CurrentAddress);
2458
2459 /* Check for overlap */
2460 if (CurrentPte == PointerPte)
2461 {
2462 /* Skip the last PTE, since it overlaps with us */
2463 CurrentPte--;
2464
2465 /* And set the PTE we will merge with */
2466 ASSERT((ComboPte == NULL) || (ComboPte == PointerPte));
2467 ComboPte = PointerPte;
2468
2469 /* Get the most flexible protection by merging both */
2470 CombinedMask |= (SectionProtection | CurrentProtection);
2471 }
2472
2473 /* Loop any PTEs left */
2474 if (CurrentPte >= StartPte)
2475 {
2476 /* Sanity check */
2477 ASSERT(StartPte < LastPte);
2478
2479 /* Make sure we don't overflow past the last PTE in the driver */
2480 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
2481 ASSERT(CurrentPte >= StartPte);
2482
2483 /* Compute the protection and set it */
2484 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
2485 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
2486 }
2487
2488 /* Set new state */
2489 StartPte = PointerPte;
2490 CurrentAddress = BaseAddress + Size - 1;
2491 CurrentProtection = SectionProtection;
2492
2493 /* Next */
2494 Sections--;
2495 Section++;
2496 }
2497
2498 /* Is there a leftover section to merge? */
2499 if (ComboPte)
2500 {
2501 /* Compute and set the protection */
2502 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
2503 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
2504
2505 /* Handle overlap */
2506 if (ComboPte == StartPte) StartPte++;
2507 }
2508
2509 /* Finally, handle the last section */
2510 CurrentPte = MiAddressToPte(CurrentAddress);
2511 if ((StartPte < LastPte) && (CurrentPte >= StartPte))
2512 {
2513 /* Handle overlap */
2514 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
2515 ASSERT(CurrentPte >= StartPte);
2516
2517 /* Compute and set the protection */
2518 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
2519 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
2520 }
2521 }
2522
2523 VOID
2524 NTAPI
2525 MiSetPagingOfDriver(IN PMMPTE PointerPte,
2526 IN PMMPTE LastPte)
2527 {
2528 PVOID ImageBase;
2529 PETHREAD CurrentThread = PsGetCurrentThread();
2530 PFN_COUNT PageCount = 0;
2531 PFN_NUMBER PageFrameIndex;
2532 PMMPFN Pfn1;
2533 PAGED_CODE();
2534
2535 /* Get the driver's base address */
2536 ImageBase = MiPteToAddress(PointerPte);
2537 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
2538
2539 /* If this is a large page, it's stuck in physical memory */
2540 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
2541
2542 /* Lock the working set */
2543 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
2544
2545 /* Loop the PTEs */
2546 while (PointerPte <= LastPte)
2547 {
2548 /* Check for valid PTE */
2549 if (PointerPte->u.Hard.Valid == 1)
2550 {
2551 PageFrameIndex = PFN_FROM_PTE(PointerPte);
2552 Pfn1 = MiGetPfnEntry(PageFrameIndex);
2553 ASSERT(Pfn1->u2.ShareCount == 1);
2554
2555 /* No working sets in ReactOS yet */
2556 PageCount++;
2557 }
2558
2559 ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE);
2560 PointerPte++;
2561 }
2562
2563 /* Release the working set */
2564 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
2565
2566 /* Do we have any driver pages? */
2567 if (PageCount)
2568 {
2569 /* Update counters */
2570 InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount);
2571 }
2572 }
2573
2574 VOID
2575 NTAPI
2576 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
2577 {
2578 ULONG_PTR ImageBase;
2579 PIMAGE_NT_HEADERS NtHeaders;
2580 ULONG Sections, Alignment, Size;
2581 PIMAGE_SECTION_HEADER Section;
2582 PMMPTE PointerPte = NULL, LastPte = NULL;
2583 if (MmDisablePagingExecutive) return;
2584
2585 /* Get the driver base address and its NT header */
2586 ImageBase = (ULONG_PTR)LdrEntry->DllBase;
2587 NtHeaders = RtlImageNtHeader((PVOID)ImageBase);
2588 if (!NtHeaders) return;
2589
2590 /* Get the sections and their alignment */
2591 Sections = NtHeaders->FileHeader.NumberOfSections;
2592 Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1;
2593
2594 /* Loop each section */
2595 Section = IMAGE_FIRST_SECTION(NtHeaders);
2596 while (Sections)
2597 {
2598 /* Find PAGE or .edata */
2599 if ((*(PULONG)Section->Name == 'EGAP') ||
2600 (*(PULONG)Section->Name == 'ade.'))
2601 {
2602 /* Had we already done some work? */
2603 if (!PointerPte)
2604 {
2605 /* Nope, setup the first PTE address */
2606 PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase +
2607 Section->
2608 VirtualAddress));
2609 }
2610
2611 /* Compute the size */
2612 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
2613
2614 /* Find the last PTE that maps this section */
2615 LastPte = MiAddressToPte(ImageBase +
2616 Section->VirtualAddress +
2617 Alignment +
2618 Size -
2619 PAGE_SIZE);
2620 }
2621 else
2622 {
2623 /* Had we found a section before? */
2624 if (PointerPte)
2625 {
2626 /* Mark it as pageable */
2627 MiSetPagingOfDriver(PointerPte, LastPte);
2628 PointerPte = NULL;
2629 }
2630 }
2631
2632 /* Keep searching */
2633 Sections--;
2634 Section++;
2635 }
2636
2637 /* Handle the straggler */
2638 if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte);
2639 }
2640
2641 BOOLEAN
2642 NTAPI
2643 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
2644 {
2645 PIMAGE_NT_HEADERS NtHeader;
2646 PAGED_CODE();
2647
2648 /* Get NT Headers */
2649 NtHeader = RtlImageNtHeader(BaseAddress);
2650 if (NtHeader)
2651 {
2652 /* Check if this image is only safe for UP while we have 2+ CPUs */
2653 if ((KeNumberProcessors > 1) &&
2654 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
2655 {
2656 /* Fail */
2657 return FALSE;
2658 }
2659 }
2660
2661 /* Otherwise, it's safe */
2662 return TRUE;
2663 }
2664
2665 NTSTATUS
2666 NTAPI
2667 MmCheckSystemImage(IN HANDLE ImageHandle,
2668 IN BOOLEAN PurgeSection)
2669 {
2670 NTSTATUS Status;
2671 HANDLE SectionHandle;
2672 PVOID ViewBase = NULL;
2673 SIZE_T ViewSize = 0;
2674 IO_STATUS_BLOCK IoStatusBlock;
2675 FILE_STANDARD_INFORMATION FileStandardInfo;
2676 KAPC_STATE ApcState;
2677 PIMAGE_NT_HEADERS NtHeaders;
2678 OBJECT_ATTRIBUTES ObjectAttributes;
2679 PAGED_CODE();
2680
2681 /* Setup the object attributes */
2682 InitializeObjectAttributes(&ObjectAttributes,
2683 NULL,
2684 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2685 NULL,
2686 NULL);
2687
2688 /* Create a section for the DLL */
2689 Status = ZwCreateSection(&SectionHandle,
2690 SECTION_MAP_EXECUTE,
2691 &ObjectAttributes,
2692 NULL,
2693 PAGE_EXECUTE,
2694 SEC_IMAGE,
2695 ImageHandle);
2696 if (!NT_SUCCESS(Status))
2697 {
2698 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status);
2699 return Status;
2700 }
2701
2702 /* Make sure we're in the system process */
2703 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
2704
2705 /* Map it */
2706 Status = ZwMapViewOfSection(SectionHandle,
2707 NtCurrentProcess(),
2708 &ViewBase,
2709 0,
2710 0,
2711 NULL,
2712 &ViewSize,
2713 ViewShare,
2714 0,
2715 PAGE_EXECUTE);
2716 if (!NT_SUCCESS(Status))
2717 {
2718 /* We failed, close the handle and return */
2719 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status);
2720 KeUnstackDetachProcess(&ApcState);
2721 ZwClose(SectionHandle);
2722 return Status;
2723 }
2724
2725 /* Now query image information */
2726 Status = ZwQueryInformationFile(ImageHandle,
2727 &IoStatusBlock,
2728 &FileStandardInfo,
2729 sizeof(FileStandardInfo),
2730 FileStandardInformation);
2731 if (NT_SUCCESS(Status))
2732 {
2733 /* First, verify the checksum */
2734 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
2735 ViewSize,
2736 FileStandardInfo.
2737 EndOfFile.LowPart))
2738 {
2739 /* Set checksum failure */
2740 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2741 goto Fail;
2742 }
2743
2744 /* Make sure it's a real image */
2745 NtHeaders = RtlImageNtHeader(ViewBase);
2746 if (!NtHeaders)
2747 {
2748 /* Set checksum failure */
2749 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2750 goto Fail;
2751 }
2752
2753 /* Make sure it's for the correct architecture */
2754 if ((NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) ||
2755 (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC))
2756 {
2757 /* Set protection failure */
2758 Status = STATUS_INVALID_IMAGE_PROTECT;
2759 goto Fail;
2760 }
2761
2762 /* Check that it's a valid SMP image if we have more then one CPU */
2763 if (!MmVerifyImageIsOkForMpUse(ViewBase))
2764 {
2765 /* Otherwise it's not the right image */
2766 Status = STATUS_IMAGE_MP_UP_MISMATCH;
2767 }
2768 }
2769
2770 /* Unmap the section, close the handle, and return status */
2771 Fail:
2772 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2773 KeUnstackDetachProcess(&ApcState);
2774 ZwClose(SectionHandle);
2775 return Status;
2776 }
2777
2778 NTSTATUS
2779 NTAPI
2780 MmLoadSystemImage(IN PUNICODE_STRING FileName,
2781 IN PUNICODE_STRING NamePrefix OPTIONAL,
2782 IN PUNICODE_STRING LoadedName OPTIONAL,
2783 IN ULONG Flags,
2784 OUT PVOID *ModuleObject,
2785 OUT PVOID *ImageBaseAddress)
2786 {
2787 PVOID ModuleLoadBase = NULL;
2788 NTSTATUS Status;
2789 HANDLE FileHandle = NULL;
2790 OBJECT_ATTRIBUTES ObjectAttributes;
2791 IO_STATUS_BLOCK IoStatusBlock;
2792 PIMAGE_NT_HEADERS NtHeader;
2793 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
2794 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
2795 ULONG EntrySize, DriverSize;
2796 PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS;
2797 PCHAR MissingApiName, Buffer;
2798 PWCHAR MissingDriverName;
2799 HANDLE SectionHandle;
2800 ACCESS_MASK DesiredAccess;
2801 PVOID Section = NULL;
2802 BOOLEAN LockOwned = FALSE;
2803 PLIST_ENTRY NextEntry;
2804 IMAGE_INFO ImageInfo;
2805 STRING AnsiTemp;
2806 PAGED_CODE();
2807
2808 /* Detect session-load */
2809 if (Flags)
2810 {
2811 /* Sanity checks */
2812 ASSERT(NamePrefix == NULL);
2813 ASSERT(LoadedName == NULL);
2814
2815 /* Make sure the process is in session too */
2816 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
2817 }
2818
2819 /* Allocate a buffer we'll use for names */
2820 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
2821 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2822
2823 /* Check for a separator */
2824 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2825 {
2826 PWCHAR p;
2827 ULONG BaseLength;
2828
2829 /* Loop the path until we get to the base name */
2830 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
2831 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
2832
2833 /* Get the length */
2834 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
2835 BaseLength *= sizeof(WCHAR);
2836
2837 /* Setup the string */
2838 BaseName.Length = (USHORT)BaseLength;
2839 BaseName.Buffer = p;
2840 }
2841 else
2842 {
2843 /* Otherwise, we already have a base name */
2844 BaseName.Length = FileName->Length;
2845 BaseName.Buffer = FileName->Buffer;
2846 }
2847
2848 /* Setup the maximum length */
2849 BaseName.MaximumLength = BaseName.Length;
2850
2851 /* Now compute the base directory */
2852 BaseDirectory = *FileName;
2853 BaseDirectory.Length -= BaseName.Length;
2854 BaseDirectory.MaximumLength = BaseDirectory.Length;
2855
2856 /* And the prefix, which for now is just the name itself */
2857 PrefixName = *FileName;
2858
2859 /* Check if we have a prefix */
2860 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
2861
2862 /* Check if we already have a name, use it instead */
2863 if (LoadedName) BaseName = *LoadedName;
2864
2865 /* Check for loader snap debugging */
2866 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS)
2867 {
2868 /* Print out standard string */
2869 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2870 &PrefixName, &BaseName, Flags ? "in session space" : "");
2871 }
2872
2873 /* Acquire the load lock */
2874 LoaderScan:
2875 ASSERT(LockOwned == FALSE);
2876 LockOwned = TRUE;
2877 KeEnterCriticalRegion();
2878 KeWaitForSingleObject(&MmSystemLoadLock,
2879 WrVirtualMemory,
2880 KernelMode,
2881 FALSE,
2882 NULL);
2883
2884 /* Scan the module list */
2885 NextEntry = PsLoadedModuleList.Flink;
2886 while (NextEntry != &PsLoadedModuleList)
2887 {
2888 /* Get the entry and compare the names */
2889 LdrEntry = CONTAINING_RECORD(NextEntry,
2890 LDR_DATA_TABLE_ENTRY,
2891 InLoadOrderLinks);
2892 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
2893 {
2894 /* Found it, break out */
2895 break;
2896 }
2897
2898 /* Keep scanning */
2899 NextEntry = NextEntry->Flink;
2900 }
2901
2902 /* Check if we found the image */
2903 if (NextEntry != &PsLoadedModuleList)
2904 {
2905 /* Check if we had already mapped a section */
2906 if (Section)
2907 {
2908 /* Dereference and clear */
2909 ObDereferenceObject(Section);
2910 Section = NULL;
2911 }
2912
2913 /* Check if this was supposed to be a session load */
2914 if (!Flags)
2915 {
2916 /* It wasn't, so just return the data */
2917 *ModuleObject = LdrEntry;
2918 *ImageBaseAddress = LdrEntry->DllBase;
2919 Status = STATUS_IMAGE_ALREADY_LOADED;
2920 }
2921 else
2922 {
2923 /* We don't support session loading yet */
2924 DPRINT1("Unsupported Session-Load!\n");
2925 while (TRUE);
2926 }
2927
2928 /* Do cleanup */
2929 goto Quickie;
2930 }
2931 else if (!Section)
2932 {
2933 /* It wasn't loaded, and we didn't have a previous attempt */
2934 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
2935 KeLeaveCriticalRegion();
2936 LockOwned = FALSE;
2937
2938 /* Check if KD is enabled */
2939 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
2940 {
2941 /* FIXME: Attempt to get image from KD */
2942 }
2943
2944 /* We don't have a valid entry */
2945 LdrEntry = NULL;
2946
2947 /* Setup image attributes */
2948 InitializeObjectAttributes(&ObjectAttributes,
2949 FileName,
2950 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2951 NULL,
2952 NULL);
2953
2954 /* Open the image */
2955 Status = ZwOpenFile(&FileHandle,
2956 FILE_EXECUTE,
2957 &ObjectAttributes,
2958 &IoStatusBlock,
2959 FILE_SHARE_READ | FILE_SHARE_DELETE,
2960 0);
2961 if (!NT_SUCCESS(Status))
2962 {
2963 DPRINT1("ZwOpenFile failed with status 0x%x\n", Status);
2964 goto Quickie;
2965 }
2966
2967 /* Validate it */
2968 Status = MmCheckSystemImage(FileHandle, FALSE);
2969 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
2970 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
2971 (Status == STATUS_INVALID_IMAGE_PROTECT))
2972 {
2973 /* Fail loading */
2974 goto Quickie;
2975 }
2976
2977 /* Check if this is a session-load */
2978 if (Flags)
2979 {
2980 /* Then we only need read and execute */
2981 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
2982 }
2983 else
2984 {
2985 /* Otherwise, we can allow write access */
2986 DesiredAccess = SECTION_ALL_ACCESS;
2987 }
2988
2989 /* Initialize the attributes for the section */
2990 InitializeObjectAttributes(&ObjectAttributes,
2991 NULL,
2992 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2993 NULL,
2994 NULL);
2995
2996 /* Create the section */
2997 Status = ZwCreateSection(&SectionHandle,
2998 DesiredAccess,
2999 &ObjectAttributes,
3000 NULL,
3001 PAGE_EXECUTE,
3002 SEC_IMAGE,
3003 FileHandle);
3004 if (!NT_SUCCESS(Status))
3005 {
3006 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status);
3007 goto Quickie;
3008 }
3009
3010 /* Now get the section pointer */
3011 Status = ObReferenceObjectByHandle(SectionHandle,
3012 SECTION_MAP_EXECUTE,
3013 MmSectionObjectType,
3014 KernelMode,
3015 &Section,
3016 NULL);
3017 ZwClose(SectionHandle);
3018 if (!NT_SUCCESS(Status)) goto Quickie;
3019
3020 /* Check if this was supposed to be a session-load */
3021 if (Flags)
3022 {
3023 /* We don't support session loading yet */
3024 DPRINT1("Unsupported Session-Load!\n");
3025 while (TRUE);
3026 }
3027
3028 /* Check the loader list again, we should end up in the path below */
3029 goto LoaderScan;
3030 }
3031 else
3032 {
3033 /* We don't have a valid entry */
3034 LdrEntry = NULL;
3035 }
3036
3037 /* Load the image */
3038 Status = MiLoadImageSection(&Section,
3039 &ModuleLoadBase,
3040 FileName,
3041 FALSE,
3042 NULL);
3043 ASSERT(Status != STATUS_ALREADY_COMMITTED);
3044
3045 /* Get the size of the driver */
3046 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
3047
3048 /* Make sure we're not being loaded into session space */
3049 if (!Flags)
3050 {
3051 /* Check for success */
3052 if (NT_SUCCESS(Status))
3053 {
3054 /* Support large pages for drivers */
3055 MiUseLargeDriverPage(DriverSize / PAGE_SIZE,
3056 &ModuleLoadBase,
3057 &BaseName,
3058 TRUE);
3059 }
3060
3061 /* Dereference the section */
3062 ObDereferenceObject(Section);
3063 Section = NULL;
3064 }
3065
3066 /* Check for failure of the load earlier */
3067 if (!NT_SUCCESS(Status))
3068 {
3069 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status);
3070 goto Quickie;
3071 }
3072
3073 /* Relocate the driver */
3074 Status = LdrRelocateImageWithBias(ModuleLoadBase,
3075 0,
3076 "SYSLDR",
3077 STATUS_SUCCESS,
3078 STATUS_CONFLICTING_ADDRESSES,
3079 STATUS_INVALID_IMAGE_FORMAT);
3080 if (!NT_SUCCESS(Status))
3081 {
3082 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status);
3083 goto Quickie;
3084 }
3085
3086 /* Get the NT Header */
3087 NtHeader = RtlImageNtHeader(ModuleLoadBase);
3088
3089 /* Calculate the size we'll need for the entry and allocate it */
3090 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
3091 BaseName.Length +
3092 sizeof(UNICODE_NULL);
3093
3094 /* Allocate the entry */
3095 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
3096 if (!LdrEntry)
3097 {
3098 /* Fail */
3099 Status = STATUS_INSUFFICIENT_RESOURCES;
3100 goto Quickie;
3101 }
3102
3103 /* Setup the entry */
3104 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
3105 LdrEntry->LoadCount = 1;
3106 LdrEntry->LoadedImports = LoadedImports;
3107 LdrEntry->PatchInformation = NULL;
3108
3109 /* Check the version */
3110 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
3111 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
3112 {
3113 /* Mark this image as a native image */
3114 LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
3115 }
3116
3117 /* Setup the rest of the entry */
3118 LdrEntry->DllBase = ModuleLoadBase;
3119 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
3120 NtHeader->OptionalHeader.AddressOfEntryPoint);
3121 LdrEntry->SizeOfImage = DriverSize;
3122 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
3123 LdrEntry->SectionPointer = Section;
3124
3125 /* Now write the DLL name */
3126 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
3127 LdrEntry->BaseDllName.Length = BaseName.Length;
3128 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
3129
3130 /* Copy and null-terminate it */
3131 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
3132 BaseName.Buffer,
3133 BaseName.Length);
3134 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
3135
3136 /* Now allocate the full name */
3137 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
3138 PrefixName.Length +
3139 sizeof(UNICODE_NULL),
3140 TAG_LDR_WSTR);
3141 if (!LdrEntry->FullDllName.Buffer)
3142 {
3143 /* Don't fail, just set it to zero */
3144 LdrEntry->FullDllName.Length = 0;
3145 LdrEntry->FullDllName.MaximumLength = 0;
3146 }
3147 else
3148 {
3149 /* Set it up */
3150 LdrEntry->FullDllName.Length = PrefixName.Length;
3151 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
3152
3153 /* Copy and null-terminate */
3154 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
3155 PrefixName.Buffer,
3156 PrefixName.Length);
3157 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
3158 }
3159
3160 /* Add the entry */
3161 MiProcessLoaderEntry(LdrEntry, TRUE);
3162
3163 /* Resolve imports */
3164 MissingApiName = Buffer;
3165 Status = MiResolveImageReferences(ModuleLoadBase,
3166 &BaseDirectory,
3167 NULL,
3168 &MissingApiName,
3169 &MissingDriverName,
3170 &LoadedImports);
3171 if (!NT_SUCCESS(Status))
3172 {
3173 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status);
3174
3175 /* Fail */
3176 MiProcessLoaderEntry(LdrEntry, FALSE);
3177
3178 /* Check if we need to free the name */
3179 if (LdrEntry->FullDllName.Buffer)
3180 {
3181 /* Free it */
3182 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR);
3183 }
3184
3185 /* Free the entry itself */
3186 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
3187 LdrEntry = NULL;
3188 goto Quickie;
3189 }
3190
3191 /* Update the loader entry */
3192 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
3193 LDRP_ENTRY_PROCESSED |
3194 LDRP_MM_LOADED);
3195 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
3196 LdrEntry->LoadedImports = LoadedImports;
3197
3198 /* FIXME: Call driver verifier's loader function */
3199
3200 /* Write-protect the system image */
3201 MiWriteProtectSystemImage(LdrEntry->DllBase);
3202
3203 /* Check if notifications are enabled */
3204 if (PsImageNotifyEnabled)
3205 {
3206 /* Fill out the notification data */
3207 ImageInfo.Properties = 0;
3208 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
3209 ImageInfo.SystemModeImage = TRUE;
3210 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
3211 ImageInfo.ImageBase = LdrEntry->DllBase;
3212 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
3213
3214 /* Send the notification */
3215 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
3216 }
3217
3218 #if defined(KDBG) || defined(_WINKD_)
3219 /* MiCacheImageSymbols doesn't detect rossym */
3220 if (TRUE)
3221 #else
3222 /* Check if there's symbols */
3223 if (MiCacheImageSymbols(LdrEntry->DllBase))
3224 #endif
3225 {
3226 /* Check if the system root is present */
3227 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
3228 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
3229 {
3230 /* Add the system root */
3231 UnicodeTemp = PrefixName;
3232 UnicodeTemp.Buffer += 11;
3233 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
3234 sprintf_nt(Buffer,
3235 "%ws%wZ",
3236 &SharedUserData->NtSystemRoot[2],
3237 &UnicodeTemp);
3238 }
3239 else
3240 {
3241 /* Build the name */
3242 sprintf_nt(Buffer, "%wZ", &BaseName);
3243 }
3244
3245 /* Setup the ansi string */
3246 RtlInitString(&AnsiTemp, Buffer);
3247
3248 /* Notify the debugger */
3249 DbgLoadImageSymbols(&AnsiTemp,
3250 LdrEntry->DllBase,
3251 (ULONG_PTR)ZwCurrentProcess());
3252 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
3253 }
3254
3255 /* Page the driver */
3256 ASSERT(Section == NULL);
3257 MiEnablePagingOfDriver(LdrEntry);
3258
3259 /* Return pointers */
3260 *ModuleObject = LdrEntry;
3261 *ImageBaseAddress = LdrEntry->DllBase;
3262
3263 Quickie:
3264 /* Check if we have the lock acquired */
3265 if (LockOwned)
3266 {
3267 /* Release the lock */
3268 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
3269 KeLeaveCriticalRegion();
3270 LockOwned = FALSE;
3271 }
3272
3273 /* If we have a file handle, close it */
3274 if (FileHandle) ZwClose(FileHandle);
3275
3276 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */
3277 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */
3278
3279 /* Free the name buffer and return status */
3280 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
3281 return Status;
3282 }
3283
3284 PLDR_DATA_TABLE_ENTRY
3285 NTAPI
3286 MiLookupDataTableEntry(IN PVOID Address)
3287 {
3288 PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL;
3289 PLIST_ENTRY NextEntry;
3290 PAGED_CODE();
3291
3292 /* Loop entries */
3293 NextEntry = PsLoadedModuleList.Flink;
3294 do
3295 {
3296 /* Get the loader entry */
3297 LdrEntry = CONTAINING_RECORD(NextEntry,
3298 LDR_DATA_TABLE_ENTRY,
3299 InLoadOrderLinks);
3300
3301 /* Check if the address matches */
3302 if ((Address >= LdrEntry->DllBase) &&
3303 (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase +
3304 LdrEntry->SizeOfImage)))
3305 {
3306 /* Found a match */
3307 FoundEntry = LdrEntry;
3308 break;
3309 }
3310
3311 /* Move on */
3312 NextEntry = NextEntry->Flink;
3313 } while(NextEntry != &PsLoadedModuleList);
3314
3315 /* Return the entry */
3316 return FoundEntry;
3317 }
3318
3319 /* PUBLIC FUNCTIONS ***********************************************************/
3320
3321 /*
3322 * @implemented
3323 */
3324 PVOID
3325 NTAPI
3326 MmPageEntireDriver(IN PVOID AddressWithinSection)
3327 {
3328 PMMPTE StartPte, EndPte;
3329 PLDR_DATA_TABLE_ENTRY LdrEntry;
3330 PAGED_CODE();
3331
3332 /* Get the loader entry */
3333 LdrEntry = MiLookupDataTableEntry(AddressWithinSection);
3334 if (!LdrEntry) return NULL;
3335
3336 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
3337 if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer))
3338 {
3339 /* Don't do anything, just return the base address */
3340 return LdrEntry->DllBase;
3341 }
3342
3343 /* Wait for active DPCs to finish before we page out the driver */
3344 KeFlushQueuedDpcs();
3345
3346 /* Get the PTE range for the whole driver image */
3347 StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase);
3348 EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);
3349
3350 /* Enable paging for the PTE range */
3351 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE);
3352 MiSetPagingOfDriver(StartPte, EndPte);
3353
3354 /* Return the base address */
3355 return LdrEntry->DllBase;
3356 }
3357
3358 /*
3359 * @unimplemented
3360 */
3361 VOID
3362 NTAPI
3363 MmResetDriverPaging(IN PVOID AddressWithinSection)
3364 {
3365 UNIMPLEMENTED;
3366 }
3367
3368 /*
3369 * @implemented
3370 */
3371 PVOID
3372 NTAPI
3373 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
3374 {
3375 PVOID ProcAddress = NULL;
3376 ANSI_STRING AnsiRoutineName;
3377 NTSTATUS Status;
3378 PLIST_ENTRY NextEntry;
3379 PLDR_DATA_TABLE_ENTRY LdrEntry;
3380 BOOLEAN Found = FALSE;
3381 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
3382 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
3383 ULONG Modules = 0;
3384
3385 /* Convert routine to ansi name */
3386 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
3387 SystemRoutineName,
3388 TRUE);
3389 if (!NT_SUCCESS(Status)) return NULL;
3390
3391 /* Lock the list */
3392 KeEnterCriticalRegion();
3393 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
3394
3395 /* Loop the loaded module list */
3396 NextEntry = PsLoadedModuleList.Flink;
3397 while (NextEntry != &PsLoadedModuleList)
3398 {
3399 /* Get the entry */
3400 LdrEntry = CONTAINING_RECORD(NextEntry,
3401 LDR_DATA_TABLE_ENTRY,
3402 InLoadOrderLinks);
3403
3404 /* Check if it's the kernel or HAL */
3405 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
3406 {
3407 /* Found it */
3408 Found = TRUE;
3409 Modules++;
3410 }
3411 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
3412 {
3413 /* Found it */
3414 Found = TRUE;
3415 Modules++;
3416 }
3417
3418 /* Check if we found a valid binary */
3419 if (Found)
3420 {
3421 /* Find the procedure name */
3422 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
3423 &AnsiRoutineName);
3424
3425 /* Break out if we found it or if we already tried both modules */
3426 if (ProcAddress) break;
3427 if (Modules == 2) break;
3428 }
3429
3430 /* Keep looping */
3431 NextEntry = NextEntry->Flink;
3432 }
3433
3434 /* Release the lock */
3435 ExReleaseResourceLite(&PsLoadedModuleResource);
3436 KeLeaveCriticalRegion();
3437
3438 /* Free the string and return */
3439 RtlFreeAnsiString(&AnsiRoutineName);
3440 return ProcAddress;
3441 }
3442
3443 /* EOF */