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