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