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