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