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