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