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