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