[NTOS]: Read almost all the Memory Management variables into the system configuration...
[reactos.git] / reactos / ntoskrnl / mm / sysldr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/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 PVOID MmUnloadedDrivers;
43 PVOID MmLastUnloadedDrivers;
44 PVOID MmTriageActionTaken;
45 PVOID KernelVerifier;
46
47 BOOLEAN MmMakeLowMemory;
48 BOOLEAN MmEnforceWriteProtection = TRUE;
49
50 /* FUNCTIONS ******************************************************************/
51
52 PVOID
53 NTAPI
54 MiCacheImageSymbols(IN PVOID BaseAddress)
55 {
56 ULONG DebugSize;
57 PVOID DebugDirectory = NULL;
58 PAGED_CODE();
59
60 /* Make sure it's safe to access the image */
61 _SEH2_TRY
62 {
63 /* Get the debug directory */
64 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
65 TRUE,
66 IMAGE_DIRECTORY_ENTRY_DEBUG,
67 &DebugSize);
68 }
69 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
70 {
71 /* Nothing */
72 }
73 _SEH2_END;
74
75 /* Return the directory */
76 return DebugDirectory;
77 }
78
79 NTSTATUS
80 NTAPI
81 MiLoadImageSection(IN OUT PVOID *SectionPtr,
82 OUT PVOID *ImageBase,
83 IN PUNICODE_STRING FileName,
84 IN BOOLEAN SessionLoad,
85 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
86 {
87 PROS_SECTION_OBJECT Section = *SectionPtr;
88 NTSTATUS Status;
89 PEPROCESS Process;
90 PVOID Base = NULL;
91 SIZE_T ViewSize = 0;
92 KAPC_STATE ApcState;
93 LARGE_INTEGER SectionOffset = {{0, 0}};
94 BOOLEAN LoadSymbols = FALSE;
95 PFN_NUMBER PteCount;
96 PMMPTE PointerPte, LastPte;
97 PVOID DriverBase;
98 MMPTE TempPte;
99 PAGED_CODE();
100
101 /* Detect session load */
102 if (SessionLoad)
103 {
104 /* Fail */
105 DPRINT1("Session loading not yet supported!\n");
106 while (TRUE);
107 }
108
109 /* Not session load, shouldn't have an entry */
110 ASSERT(LdrEntry == NULL);
111
112 /* Attach to the system process */
113 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
114
115 /* Check if we need to load symbols */
116 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
117 {
118 /* Yes we do */
119 LoadSymbols = TRUE;
120 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
121 }
122
123 /* Map the driver */
124 Process = PsGetCurrentProcess();
125 Status = MmMapViewOfSection(Section,
126 Process,
127 &Base,
128 0,
129 0,
130 &SectionOffset,
131 &ViewSize,
132 ViewUnmap,
133 0,
134 PAGE_EXECUTE);
135
136 /* Re-enable the flag */
137 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
138
139 /* Check if we failed with distinguished status code */
140 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
141 {
142 /* Change it to something more generic */
143 Status = STATUS_INVALID_IMAGE_FORMAT;
144 }
145
146 /* Now check if we failed */
147 if (!NT_SUCCESS(Status))
148 {
149 /* Detach and return */
150 KeUnstackDetachProcess(&ApcState);
151 return Status;
152 }
153
154 /* Reserve system PTEs needed */
155 PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
156 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
157 if (!PointerPte) return STATUS_INSUFFICIENT_RESOURCES;
158
159 /* New driver base */
160 LastPte = PointerPte + PteCount;
161 DriverBase = MiPteToAddress(PointerPte);
162
163 /* The driver is here */
164 *ImageBase = DriverBase;
165
166 /* Loop the new driver PTEs */
167 TempPte = ValidKernelPte;
168 while (PointerPte < LastPte)
169 {
170 /* Allocate a page */
171 TempPte.u.Hard.PageFrameNumber = MmAllocPage(MC_NPPOOL);
172
173 /* Write it */
174 ASSERT(PointerPte->u.Hard.Valid == 0);
175 ASSERT(TempPte.u.Hard.Valid == 1);
176 *PointerPte = TempPte;
177
178 /* Move on */
179 PointerPte++;
180 }
181
182 /* Copy the image */
183 RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
184
185 /* Now unmap the view */
186 Status = MmUnmapViewOfSection(Process, Base);
187 ASSERT(NT_SUCCESS(Status));
188
189 /* Detach and return status */
190 KeUnstackDetachProcess(&ApcState);
191 return Status;
192 }
193
194 NTSTATUS
195 NTAPI
196 MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
197 {
198 SIZE_T i;
199
200 /* Check if there's no imports or if we're a boot driver */
201 if ((ImportList == (PVOID)-1) ||
202 (ImportList == (PVOID)-2) ||
203 (ImportList->Count == 0))
204 {
205 /* Then there's nothing to do */
206 return STATUS_SUCCESS;
207 }
208
209 /* Otherwise, FIXME */
210 DPRINT1("%u imports not dereferenced!\n", ImportList->Count);
211 for (i = 0; i < ImportList->Count; i++)
212 {
213 DPRINT1("%wZ <%wZ>\n", &ImportList->Entry[i]->FullDllName, &ImportList->Entry[i]->BaseDllName);
214 }
215 return STATUS_UNSUCCESSFUL;
216 }
217
218 VOID
219 NTAPI
220 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
221 {
222 PAGED_CODE();
223
224 /* Check if there's no imports or we're a boot driver or only one entry */
225 if ((LdrEntry->LoadedImports == (PVOID)-1) ||
226 (LdrEntry->LoadedImports == (PVOID)-2) ||
227 ((ULONG_PTR)LdrEntry->LoadedImports & 1))
228 {
229 /* Nothing to do */
230 return;
231 }
232
233 /* Otherwise, free the import list */
234 ExFreePool(LdrEntry->LoadedImports);
235 }
236
237 PVOID
238 NTAPI
239 MiFindExportedRoutineByName(IN PVOID DllBase,
240 IN PANSI_STRING ExportName)
241 {
242 PULONG NameTable;
243 PUSHORT OrdinalTable;
244 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
245 LONG Low = 0, Mid = 0, High, Ret;
246 USHORT Ordinal;
247 PVOID Function;
248 ULONG ExportSize;
249 PULONG ExportTable;
250 PAGED_CODE();
251
252 /* Get the export directory */
253 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
254 TRUE,
255 IMAGE_DIRECTORY_ENTRY_EXPORT,
256 &ExportSize);
257 if (!ExportDirectory) return NULL;
258
259 /* Setup name tables */
260 NameTable = (PULONG)((ULONG_PTR)DllBase +
261 ExportDirectory->AddressOfNames);
262 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
263 ExportDirectory->AddressOfNameOrdinals);
264
265 /* Do a binary search */
266 High = ExportDirectory->NumberOfNames - 1;
267 while (High >= Low)
268 {
269 /* Get new middle value */
270 Mid = (Low + High) >> 1;
271
272 /* Compare name */
273 Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
274 if (Ret < 0)
275 {
276 /* Update high */
277 High = Mid - 1;
278 }
279 else if (Ret > 0)
280 {
281 /* Update low */
282 Low = Mid + 1;
283 }
284 else
285 {
286 /* We got it */
287 break;
288 }
289 }
290
291 /* Check if we couldn't find it */
292 if (High < Low) return NULL;
293
294 /* Otherwise, this is the ordinal */
295 Ordinal = OrdinalTable[Mid];
296
297 /* Resolve the address and write it */
298 ExportTable = (PULONG)((ULONG_PTR)DllBase +
299 ExportDirectory->AddressOfFunctions);
300 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
301
302 /* We found it! */
303 ASSERT(!(Function > (PVOID)ExportDirectory) &&
304 (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
305 return Function;
306 }
307
308 PVOID
309 NTAPI
310 MiLocateExportName(IN PVOID DllBase,
311 IN PCHAR ExportName)
312 {
313 PULONG NameTable;
314 PUSHORT OrdinalTable;
315 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
316 LONG Low = 0, Mid = 0, High, Ret;
317 USHORT Ordinal;
318 PVOID Function;
319 ULONG ExportSize;
320 PULONG ExportTable;
321 PAGED_CODE();
322
323 /* Get the export directory */
324 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
325 TRUE,
326 IMAGE_DIRECTORY_ENTRY_EXPORT,
327 &ExportSize);
328 if (!ExportDirectory) return NULL;
329
330 /* Setup name tables */
331 NameTable = (PULONG)((ULONG_PTR)DllBase +
332 ExportDirectory->AddressOfNames);
333 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
334 ExportDirectory->AddressOfNameOrdinals);
335
336 /* Do a binary search */
337 High = ExportDirectory->NumberOfNames - 1;
338 while (High >= Low)
339 {
340 /* Get new middle value */
341 Mid = (Low + High) >> 1;
342
343 /* Compare name */
344 Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
345 if (Ret < 0)
346 {
347 /* Update high */
348 High = Mid - 1;
349 }
350 else if (Ret > 0)
351 {
352 /* Update low */
353 Low = Mid + 1;
354 }
355 else
356 {
357 /* We got it */
358 break;
359 }
360 }
361
362 /* Check if we couldn't find it */
363 if (High < Low) return NULL;
364
365 /* Otherwise, this is the ordinal */
366 Ordinal = OrdinalTable[Mid];
367
368 /* Resolve the address and write it */
369 ExportTable = (PULONG)((ULONG_PTR)DllBase +
370 ExportDirectory->AddressOfFunctions);
371 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
372
373 /* Check if the function is actually a forwarder */
374 if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
375 ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
376 {
377 /* It is, fail */
378 return NULL;
379 }
380
381 /* We found it */
382 return Function;
383 }
384
385 NTSTATUS
386 NTAPI
387 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
388 IN PLIST_ENTRY ListHead)
389 {
390 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
391 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
392 PMM_DLL_INITIALIZE DllInit;
393 UNICODE_STRING RegPath, ImportName;
394 NTSTATUS Status;
395
396 /* Try to see if the image exports a DllInitialize routine */
397 DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
398 "DllInitialize");
399 if (!DllInit) return STATUS_SUCCESS;
400
401 /* Do a temporary copy of BaseDllName called ImportName
402 * because we'll alter the length of the string
403 */
404 ImportName.Length = LdrEntry->BaseDllName.Length;
405 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
406 ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
407
408 /* Obtain the path to this dll's service in the registry */
409 RegPath.MaximumLength = ServicesKeyName.Length +
410 ImportName.Length + sizeof(UNICODE_NULL);
411 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
412 RegPath.MaximumLength,
413 TAG_LDR_WSTR);
414
415 /* Check if this allocation was unsuccessful */
416 if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
417
418 /* Build and append the service name itself */
419 RegPath.Length = ServicesKeyName.Length;
420 RtlCopyMemory(RegPath.Buffer,
421 ServicesKeyName.Buffer,
422 ServicesKeyName.Length);
423
424 /* Check if there is a dot in the filename */
425 if (wcschr(ImportName.Buffer, L'.'))
426 {
427 /* Remove the extension */
428 ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
429 ImportName.Buffer) * sizeof(WCHAR);
430 }
431
432 /* Append service name (the basename without extension) */
433 RtlAppendUnicodeStringToString(&RegPath, &ImportName);
434
435 /* Now call the DllInit func */
436 DPRINT("Calling DllInit(%wZ)\n", &RegPath);
437 Status = DllInit(&RegPath);
438
439 /* Clean up */
440 ExFreePool(RegPath.Buffer);
441
442 /* Return status value which DllInitialize returned */
443 return Status;
444 }
445
446 VOID
447 NTAPI
448 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
449 IN BOOLEAN Insert)
450 {
451 KIRQL OldIrql;
452
453 /* Acquire module list lock */
454 KeEnterCriticalRegion();
455 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
456
457 /* Acquire the spinlock too as we will insert or remove the entry */
458 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
459
460 /* Insert or remove from the list */
461 Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
462 RemoveEntryList(&LdrEntry->InLoadOrderLinks);
463
464 /* Release locks */
465 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
466 ExReleaseResourceLite(&PsLoadedModuleResource);
467 KeLeaveCriticalRegion();
468 }
469
470 VOID
471 NTAPI
472 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
473 IN PVOID OldBase,
474 IN PVOID NewBase,
475 IN ULONG Size)
476 {
477 ULONG_PTR OldBaseTop, Delta;
478 PLDR_DATA_TABLE_ENTRY LdrEntry;
479 PLIST_ENTRY NextEntry;
480 ULONG ImportSize;
481 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
482 PULONG ImageThunk;
483
484 /* Calculate the top and delta */
485 OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
486 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
487
488 /* Loop the loader block */
489 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
490 NextEntry != &LoaderBlock->LoadOrderListHead;
491 NextEntry = NextEntry->Flink)
492 {
493 /* Get the loader entry */
494 LdrEntry = CONTAINING_RECORD(NextEntry,
495 LDR_DATA_TABLE_ENTRY,
496 InLoadOrderLinks);
497
498 /* Get the import table */
499 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
500 TRUE,
501 IMAGE_DIRECTORY_ENTRY_IMPORT,
502 &ImportSize);
503 if (!ImportDescriptor) continue;
504
505 /* Make sure we have an IAT */
506 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
507 while ((ImportDescriptor->Name) &&
508 (ImportDescriptor->OriginalFirstThunk))
509 {
510 /* Get the image thunk */
511 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
512 ImportDescriptor->FirstThunk);
513 while (*ImageThunk)
514 {
515 /* Check if it's within this module */
516 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
517 {
518 /* Relocate it */
519 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
520 ImageThunk, *ImageThunk, *ImageThunk + Delta);
521 *ImageThunk += Delta;
522 }
523
524 /* Go to the next thunk */
525 ImageThunk++;
526 }
527
528 /* Go to the next import */
529 ImportDescriptor++;
530 }
531 }
532 }
533
534 NTSTATUS
535 NTAPI
536 MiSnapThunk(IN PVOID DllBase,
537 IN PVOID ImageBase,
538 IN PIMAGE_THUNK_DATA Name,
539 IN PIMAGE_THUNK_DATA Address,
540 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
541 IN ULONG ExportSize,
542 IN BOOLEAN SnapForwarder,
543 OUT PCHAR *MissingApi)
544 {
545 BOOLEAN IsOrdinal;
546 USHORT Ordinal;
547 PULONG NameTable;
548 PUSHORT OrdinalTable;
549 PIMAGE_IMPORT_BY_NAME NameImport;
550 USHORT Hint;
551 ULONG Low = 0, Mid = 0, High;
552 LONG Ret;
553 NTSTATUS Status;
554 PCHAR MissingForwarder;
555 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
556 PULONG ExportTable;
557 ANSI_STRING DllName;
558 UNICODE_STRING ForwarderName;
559 PLIST_ENTRY NextEntry;
560 PLDR_DATA_TABLE_ENTRY LdrEntry;
561 ULONG ForwardExportSize;
562 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
563 PIMAGE_IMPORT_BY_NAME ForwardName;
564 ULONG ForwardLength;
565 IMAGE_THUNK_DATA ForwardThunk;
566 PAGED_CODE();
567
568 /* Check if this is an ordinal */
569 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
570 if ((IsOrdinal) && !(SnapForwarder))
571 {
572 /* Get the ordinal number and set it as missing */
573 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
574 ExportDirectory->Base);
575 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
576 }
577 else
578 {
579 /* Get the VA if we don't have to snap */
580 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
581 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
582
583 /* Copy the procedure name */
584 strncpy(*MissingApi,
585 (PCHAR)&NameImport->Name[0],
586 MAXIMUM_FILENAME_LENGTH - 1);
587
588 /* Setup name tables */
589 DPRINT("Import name: %s\n", NameImport->Name);
590 NameTable = (PULONG)((ULONG_PTR)DllBase +
591 ExportDirectory->AddressOfNames);
592 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
593 ExportDirectory->AddressOfNameOrdinals);
594
595 /* Get the hint and check if it's valid */
596 Hint = NameImport->Hint;
597 if ((Hint < ExportDirectory->NumberOfNames) &&
598 !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
599 {
600 /* We have a match, get the ordinal number from here */
601 Ordinal = OrdinalTable[Hint];
602 }
603 else
604 {
605 /* Do a binary search */
606 High = ExportDirectory->NumberOfNames - 1;
607 while (High >= Low)
608 {
609 /* Get new middle value */
610 Mid = (Low + High) >> 1;
611
612 /* Compare name */
613 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
614 if (Ret < 0)
615 {
616 /* Update high */
617 High = Mid - 1;
618 }
619 else if (Ret > 0)
620 {
621 /* Update low */
622 Low = Mid + 1;
623 }
624 else
625 {
626 /* We got it */
627 break;
628 }
629 }
630
631 /* Check if we couldn't find it */
632 if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
633
634 /* Otherwise, this is the ordinal */
635 Ordinal = OrdinalTable[Mid];
636 }
637 }
638
639 /* Check if the ordinal is invalid */
640 if (Ordinal >= ExportDirectory->NumberOfFunctions)
641 {
642 /* Fail */
643 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
644 }
645 else
646 {
647 /* In case the forwarder is missing */
648 MissingForwarder = NameBuffer;
649
650 /* Resolve the address and write it */
651 ExportTable = (PULONG)((ULONG_PTR)DllBase +
652 ExportDirectory->AddressOfFunctions);
653 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
654
655 /* Assume success from now on */
656 Status = STATUS_SUCCESS;
657
658 /* Check if the function is actually a forwarder */
659 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
660 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
661 {
662 /* Now assume failure in case the forwarder doesn't exist */
663 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
664
665 /* Build the forwarder name */
666 DllName.Buffer = (PCHAR)Address->u1.Function;
667 DllName.Length = strchr(DllName.Buffer, '.') -
668 DllName.Buffer +
669 sizeof(ANSI_NULL);
670 DllName.MaximumLength = DllName.Length;
671
672 /* Convert it */
673 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
674 &DllName,
675 TRUE)))
676 {
677 /* We failed, just return an error */
678 return Status;
679 }
680
681 /* Loop the module list */
682 NextEntry = PsLoadedModuleList.Flink;
683 while (NextEntry != &PsLoadedModuleList)
684 {
685 /* Get the loader entry */
686 LdrEntry = CONTAINING_RECORD(NextEntry,
687 LDR_DATA_TABLE_ENTRY,
688 InLoadOrderLinks);
689
690 /* Check if it matches */
691 if (RtlPrefixString((PSTRING)&ForwarderName,
692 (PSTRING)&LdrEntry->BaseDllName,
693 TRUE))
694 {
695 /* Get the forwarder export directory */
696 ForwardExportDirectory =
697 RtlImageDirectoryEntryToData(LdrEntry->DllBase,
698 TRUE,
699 IMAGE_DIRECTORY_ENTRY_EXPORT,
700 &ForwardExportSize);
701 if (!ForwardExportDirectory) break;
702
703 /* Allocate a name entry */
704 ForwardLength = strlen(DllName.Buffer + DllName.Length) +
705 sizeof(ANSI_NULL);
706 ForwardName = ExAllocatePoolWithTag(PagedPool,
707 sizeof(*ForwardName) +
708 ForwardLength,
709 TAG_LDR_WSTR);
710 if (!ForwardName) break;
711
712 /* Copy the data */
713 RtlCopyMemory(&ForwardName->Name[0],
714 DllName.Buffer + DllName.Length,
715 ForwardLength);
716 ForwardName->Hint = 0;
717
718 /* Set the new address */
719 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
720
721 /* Snap the forwarder */
722 Status = MiSnapThunk(LdrEntry->DllBase,
723 ImageBase,
724 &ForwardThunk,
725 &ForwardThunk,
726 ForwardExportDirectory,
727 ForwardExportSize,
728 TRUE,
729 &MissingForwarder);
730
731 /* Free the forwarder name and set the thunk */
732 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
733 Address->u1 = ForwardThunk.u1;
734 break;
735 }
736
737 /* Go to the next entry */
738 NextEntry = NextEntry->Flink;
739 }
740
741 /* Free the name */
742 RtlFreeUnicodeString(&ForwarderName);
743 }
744 }
745
746 /* Return status */
747 return Status;
748 }
749
750 NTSTATUS
751 NTAPI
752 MmUnloadSystemImage(IN PVOID ImageHandle)
753 {
754 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
755 PVOID BaseAddress = LdrEntry->DllBase;
756 NTSTATUS Status;
757 STRING TempName;
758 BOOLEAN HadEntry = FALSE;
759
760 /* Acquire the loader lock */
761 KeEnterCriticalRegion();
762 KeWaitForSingleObject(&MmSystemLoadLock,
763 WrVirtualMemory,
764 KernelMode,
765 FALSE,
766 NULL);
767
768 /* Check if this driver was loaded at boot and didn't get imports parsed */
769 if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;
770
771 /* We should still be alive */
772 ASSERT(LdrEntry->LoadCount != 0);
773 LdrEntry->LoadCount--;
774
775 /* Check if we're still loaded */
776 if (LdrEntry->LoadCount) goto Done;
777
778 /* We should cleanup... are symbols loaded */
779 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
780 {
781 /* Create the ANSI name */
782 Status = RtlUnicodeStringToAnsiString(&TempName,
783 &LdrEntry->BaseDllName,
784 TRUE);
785 if (NT_SUCCESS(Status))
786 {
787 /* Unload the symbols */
788 DbgUnLoadImageSymbols(&TempName,
789 BaseAddress,
790 (ULONG_PTR)ZwCurrentProcess());
791 RtlFreeAnsiString(&TempName);
792 }
793 }
794
795 /* FIXME: Free the driver */
796 //MmFreeSection(LdrEntry->DllBase);
797
798 /* Check if we're linked in */
799 if (LdrEntry->InLoadOrderLinks.Flink)
800 {
801 /* Remove us */
802 MiProcessLoaderEntry(LdrEntry, FALSE);
803 HadEntry = TRUE;
804 }
805
806 /* Dereference and clear the imports */
807 MiDereferenceImports(LdrEntry->LoadedImports);
808 MiClearImports(LdrEntry);
809
810 /* Check if the entry needs to go away */
811 if (HadEntry)
812 {
813 /* Check if it had a name */
814 if (LdrEntry->FullDllName.Buffer)
815 {
816 /* Free it */
817 ExFreePool(LdrEntry->FullDllName.Buffer);
818 }
819
820 /* Check if we had a section */
821 if (LdrEntry->SectionPointer)
822 {
823 /* Dereference it */
824 ObDereferenceObject(LdrEntry->SectionPointer);
825 }
826
827 /* Free the entry */
828 ExFreePool(LdrEntry);
829 }
830
831 /* Release the system lock and return */
832 Done:
833 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
834 KeLeaveCriticalRegion();
835 return STATUS_SUCCESS;
836 }
837
838 NTSTATUS
839 NTAPI
840 MiResolveImageReferences(IN PVOID ImageBase,
841 IN PUNICODE_STRING ImageFileDirectory,
842 IN PUNICODE_STRING NamePrefix OPTIONAL,
843 OUT PCHAR *MissingApi,
844 OUT PWCHAR *MissingDriver,
845 OUT PLOAD_IMPORTS *LoadImports)
846 {
847 PCHAR MissingApiBuffer = *MissingApi, ImportName;
848 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
849 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
850 PLOAD_IMPORTS LoadedImports, NewImports;
851 ULONG GdiLink, NormalLink, i;
852 BOOLEAN ReferenceNeeded, Loaded;
853 ANSI_STRING TempString;
854 UNICODE_STRING NameString, DllName;
855 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
856 PVOID ImportBase, DllBase;
857 PLIST_ENTRY NextEntry;
858 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
859 NTSTATUS Status;
860 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
861 PAGED_CODE();
862 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
863 __FUNCTION__, ImageBase, ImageFileDirectory);
864
865 /* Assume no imports */
866 *LoadImports = (PVOID)-2;
867
868 /* Get the import descriptor */
869 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
870 TRUE,
871 IMAGE_DIRECTORY_ENTRY_IMPORT,
872 &ImportSize);
873 if (!ImportDescriptor) return STATUS_SUCCESS;
874
875 /* Loop all imports to count them */
876 for (CurrentImport = ImportDescriptor;
877 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
878 CurrentImport++)
879 {
880 /* One more */
881 ImportCount++;
882 }
883
884 /* Make sure we have non-zero imports */
885 if (ImportCount)
886 {
887 /* Calculate and allocate the list we'll need */
888 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
889 LoadedImports = ExAllocatePoolWithTag(PagedPool,
890 LoadedImportsSize,
891 TAG_LDR_WSTR);
892 if (LoadedImports)
893 {
894 /* Zero it */
895 RtlZeroMemory(LoadedImports, LoadedImportsSize);
896 }
897 }
898 else
899 {
900 /* No table */
901 LoadedImports = NULL;
902 }
903
904 /* Reset the import count and loop descriptors again */
905 ImportCount = GdiLink = NormalLink = 0;
906 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
907 {
908 /* Get the name */
909 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
910
911 /* Check if this is a GDI driver */
912 GdiLink = GdiLink |
913 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
914
915 /* We can also allow dxapi */
916 NormalLink = NormalLink |
917 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
918 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
919
920 /* Check if this is a valid GDI driver */
921 if ((GdiLink) && (NormalLink))
922 {
923 /* It's not, it's importing stuff it shouldn't be! */
924 MiDereferenceImports(LoadedImports);
925 if (LoadedImports) ExFreePool(LoadedImports);
926 return STATUS_PROCEDURE_NOT_FOUND;
927 }
928
929 /* Check if this is a "core" import, which doesn't get referenced */
930 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
931 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
932 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
933 {
934 /* Don't reference this */
935 ReferenceNeeded = FALSE;
936 }
937 else
938 {
939 /* Reference these modules */
940 ReferenceNeeded = TRUE;
941 }
942
943 /* Now setup a unicode string for the import */
944 RtlInitAnsiString(&TempString, ImportName);
945 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
946 if (!NT_SUCCESS(Status))
947 {
948 /* Failed */
949 MiDereferenceImports(LoadedImports);
950 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
951 return Status;
952 }
953
954 /* We don't support name prefixes yet */
955 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
956
957 /* Remember that we haven't loaded the import at this point */
958 CheckDllState:
959 Loaded = FALSE;
960 ImportBase = NULL;
961
962 /* Loop the driver list */
963 NextEntry = PsLoadedModuleList.Flink;
964 while (NextEntry != &PsLoadedModuleList)
965 {
966 /* Get the loader entry and compare the name */
967 LdrEntry = CONTAINING_RECORD(NextEntry,
968 LDR_DATA_TABLE_ENTRY,
969 InLoadOrderLinks);
970 if (RtlEqualUnicodeString(&NameString,
971 &LdrEntry->BaseDllName,
972 TRUE))
973 {
974 /* Get the base address */
975 ImportBase = LdrEntry->DllBase;
976
977 /* Check if we haven't loaded yet, and we need references */
978 if (!(Loaded) && (ReferenceNeeded))
979 {
980 /* Make sure we're not already loading */
981 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
982 {
983 /* Increase the load count */
984 LdrEntry->LoadCount++;
985 }
986 }
987
988 /* Done, break out */
989 break;
990 }
991
992 /* Go to the next entry */
993 NextEntry = NextEntry->Flink;
994 }
995
996 /* Check if we haven't loaded the import yet */
997 if (!ImportBase)
998 {
999 /* Setup the import DLL name */
1000 DllName.MaximumLength = NameString.Length +
1001 ImageFileDirectory->Length +
1002 sizeof(UNICODE_NULL);
1003 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1004 DllName.MaximumLength,
1005 TAG_LDR_WSTR);
1006 if (DllName.Buffer)
1007 {
1008 /* Setup the base length and copy it */
1009 DllName.Length = ImageFileDirectory->Length;
1010 RtlCopyMemory(DllName.Buffer,
1011 ImageFileDirectory->Buffer,
1012 ImageFileDirectory->Length);
1013
1014 /* Now add the import name and null-terminate it */
1015 RtlAppendStringToString((PSTRING)&DllName,
1016 (PSTRING)&NameString);
1017 DllName.Buffer[(DllName.MaximumLength - 1) / sizeof(WCHAR)] = UNICODE_NULL;
1018
1019 /* Load the image */
1020 Status = MmLoadSystemImage(&DllName,
1021 NamePrefix,
1022 NULL,
1023 0,
1024 (PVOID)&DllEntry,
1025 &DllBase);
1026 if (NT_SUCCESS(Status))
1027 {
1028 /* We can free the DLL Name */
1029 ExFreePool(DllName.Buffer);
1030 }
1031 else
1032 {
1033 /* Fill out the information for the error */
1034 *MissingDriver = DllName.Buffer;
1035 *(PULONG)MissingDriver |= 1;
1036 *MissingApi = NULL;
1037 }
1038 }
1039 else
1040 {
1041 /* We're out of resources */
1042 Status = STATUS_INSUFFICIENT_RESOURCES;
1043 }
1044
1045 /* Check if we're OK until now */
1046 if (NT_SUCCESS(Status))
1047 {
1048 /* We're now loaded */
1049 Loaded = TRUE;
1050
1051 /* Sanity check */
1052 ASSERT(DllBase = DllEntry->DllBase);
1053
1054 /* Call the initialization routines */
1055 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
1056 if (!NT_SUCCESS(Status))
1057 {
1058 /* We failed, unload the image */
1059 MmUnloadSystemImage(DllEntry);
1060 while (TRUE);
1061 Loaded = FALSE;
1062 }
1063 }
1064
1065 /* Check if we failed by here */
1066 if (!NT_SUCCESS(Status))
1067 {
1068 /* Cleanup and return */
1069 RtlFreeUnicodeString(&NameString);
1070 MiDereferenceImports(LoadedImports);
1071 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1072 return Status;
1073 }
1074
1075 /* Loop again to make sure that everything is OK */
1076 goto CheckDllState;
1077 }
1078
1079 /* Check if we're support to reference this import */
1080 if ((ReferenceNeeded) && (LoadedImports))
1081 {
1082 /* Make sure we're not already loading */
1083 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1084 {
1085 /* Add the entry */
1086 LoadedImports->Entry[LoadedImports->Count] = LdrEntry;
1087 LoadedImports->Count++;
1088 }
1089 }
1090
1091 /* Free the import name */
1092 RtlFreeUnicodeString(&NameString);
1093
1094 /* Set the missing driver name and get the export directory */
1095 *MissingDriver = LdrEntry->BaseDllName.Buffer;
1096 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
1097 TRUE,
1098 IMAGE_DIRECTORY_ENTRY_EXPORT,
1099 &ExportSize);
1100 if (!ExportDirectory)
1101 {
1102 /* Cleanup and return */
1103 MiDereferenceImports(LoadedImports);
1104 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1105 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
1106 }
1107
1108 /* Make sure we have an IAT */
1109 if (ImportDescriptor->OriginalFirstThunk)
1110 {
1111 /* Get the first thunks */
1112 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
1113 ImportDescriptor->OriginalFirstThunk);
1114 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
1115 ImportDescriptor->FirstThunk);
1116
1117 /* Loop the IAT */
1118 while (OrigThunk->u1.AddressOfData)
1119 {
1120 /* Snap thunk */
1121 Status = MiSnapThunk(ImportBase,
1122 ImageBase,
1123 OrigThunk++,
1124 FirstThunk++,
1125 ExportDirectory,
1126 ExportSize,
1127 FALSE,
1128 MissingApi);
1129 if (!NT_SUCCESS(Status))
1130 {
1131 /* Cleanup and return */
1132 MiDereferenceImports(LoadedImports);
1133 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1134 return Status;
1135 }
1136
1137 /* Reset the buffer */
1138 *MissingApi = MissingApiBuffer;
1139 }
1140 }
1141
1142 /* Go to the next import */
1143 ImportDescriptor++;
1144 }
1145
1146 /* Check if we have an import list */
1147 if (LoadedImports)
1148 {
1149 /* Reset the count again, and loop entries*/
1150 ImportCount = 0;
1151 for (i = 0; i < LoadedImports->Count; i++)
1152 {
1153 if (LoadedImports->Entry[i])
1154 {
1155 /* Got an entry, OR it with 1 in case it's the single entry */
1156 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
1157 ImportCount++;
1158 }
1159 }
1160
1161 /* Check if we had no imports */
1162 if (!ImportCount)
1163 {
1164 /* Free the list and set it to no imports */
1165 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1166 LoadedImports = (PVOID)-2;
1167 }
1168 else if (ImportCount == 1)
1169 {
1170 /* Just one entry, we can free the table and only use our entry */
1171 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1172 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
1173 }
1174 else if (ImportCount != LoadedImports->Count)
1175 {
1176 /* Allocate a new list */
1177 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1178 NewImports = ExAllocatePoolWithTag(PagedPool,
1179 LoadedImportsSize,
1180 TAG_LDR_WSTR);
1181 if (NewImports)
1182 {
1183 /* Set count */
1184 NewImports->Count = 0;
1185
1186 /* Loop all the imports */
1187 for (i = 0; i < LoadedImports->Count; i++)
1188 {
1189 /* Make sure it's valid */
1190 if (LoadedImports->Entry[i])
1191 {
1192 /* Copy it */
1193 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
1194 NewImports->Count++;
1195 }
1196 }
1197
1198 /* Free the old copy */
1199 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1200 LoadedImports = NewImports;
1201 }
1202 }
1203
1204 /* Return the list */
1205 *LoadImports = LoadedImports;
1206 }
1207
1208 /* Return success */
1209 return STATUS_SUCCESS;
1210 }
1211
1212 VOID
1213 NTAPI
1214 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1215 {
1216 PLIST_ENTRY NextEntry;
1217 ULONG i = 0;
1218 PIMAGE_NT_HEADERS NtHeader;
1219 PLDR_DATA_TABLE_ENTRY LdrEntry;
1220 PIMAGE_FILE_HEADER FileHeader;
1221 BOOLEAN ValidRelocs;
1222 PIMAGE_DATA_DIRECTORY DataDirectory;
1223 PVOID DllBase, NewImageAddress;
1224 NTSTATUS Status;
1225 PMMPTE PointerPte, StartPte, LastPte;
1226 PFN_NUMBER PteCount;
1227 PMMPFN Pfn1;
1228 MMPTE TempPte, OldPte;
1229
1230 /* Loop driver list */
1231 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1232 NextEntry != &LoaderBlock->LoadOrderListHead;
1233 NextEntry = NextEntry->Flink)
1234 {
1235 /* Get the loader entry and NT header */
1236 LdrEntry = CONTAINING_RECORD(NextEntry,
1237 LDR_DATA_TABLE_ENTRY,
1238 InLoadOrderLinks);
1239 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1240
1241 /* Debug info */
1242 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1243 LdrEntry->DllBase,
1244 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
1245 &LdrEntry->FullDllName);
1246
1247 /* Skip kernel and HAL */
1248 /* ROS HACK: Skip BOOTVID/KDCOM too */
1249 i++;
1250 if (i <= 4) continue;
1251
1252 /* Skip non-drivers */
1253 if (!NtHeader) continue;
1254
1255 /* Get the file header and make sure we can relocate */
1256 FileHeader = &NtHeader->FileHeader;
1257 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1258 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1259 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1260
1261 /* Everything made sense until now, check the relocation section too */
1262 DataDirectory = &NtHeader->OptionalHeader.
1263 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1264 if (!DataDirectory->VirtualAddress)
1265 {
1266 /* We don't really have relocations */
1267 ValidRelocs = FALSE;
1268 }
1269 else
1270 {
1271 /* Make sure the size is valid */
1272 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1273 LdrEntry->SizeOfImage)
1274 {
1275 /* They're not, skip */
1276 continue;
1277 }
1278
1279 /* We have relocations */
1280 ValidRelocs = TRUE;
1281 }
1282
1283 /* Remember the original address */
1284 DllBase = LdrEntry->DllBase;
1285
1286 /* Get the first PTE and the number of PTEs we'll need */
1287 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
1288 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
1289 LastPte = StartPte + PteCount;
1290
1291 /* Loop the PTEs */
1292 while (PointerPte < LastPte)
1293 {
1294 /* Mark the page modified in the PFN database */
1295 ASSERT(PointerPte->u.Hard.Valid == 1);
1296 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1297 ASSERT(Pfn1->u3.e1.Rom == 0);
1298 Pfn1->u3.e1.Modified = TRUE;
1299
1300 /* Next */
1301 PointerPte++;
1302 }
1303
1304 /* Now reserve system PTEs for the image */
1305 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
1306 if (!PointerPte)
1307 {
1308 /* Shouldn't happen */
1309 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1310 while (TRUE);
1311 }
1312
1313 /* This is the new virtual address for the module */
1314 LastPte = PointerPte + PteCount;
1315 NewImageAddress = MiPteToAddress(PointerPte);
1316
1317 /* Sanity check */
1318 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1319 ASSERT(ExpInitializationPhase == 0);
1320
1321 /* Loop the new driver PTEs */
1322 TempPte = ValidKernelPte;
1323 while (PointerPte < LastPte)
1324 {
1325 /* Copy the old data */
1326 OldPte = *StartPte;
1327 ASSERT(OldPte.u.Hard.Valid == 1);
1328
1329 /* Set page number from the loader's memory */
1330 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
1331
1332 /* Write it */
1333 ASSERT(PointerPte->u.Hard.Valid == 0);
1334 ASSERT(TempPte.u.Hard.Valid == 1);
1335 *PointerPte = TempPte;
1336
1337 /* Move on */
1338 PointerPte++;
1339 StartPte++;
1340 }
1341
1342 /* Update position */
1343 PointerPte -= PteCount;
1344
1345 /* Sanity check */
1346 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1347
1348 /* Set the image base to the address where the loader put it */
1349 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1350
1351 /* Check if we had relocations */
1352 if (ValidRelocs)
1353 {
1354 /* Relocate the image */
1355 Status = LdrRelocateImageWithBias(NewImageAddress,
1356 0,
1357 "SYSLDR",
1358 STATUS_SUCCESS,
1359 STATUS_CONFLICTING_ADDRESSES,
1360 STATUS_INVALID_IMAGE_FORMAT);
1361 if (!NT_SUCCESS(Status))
1362 {
1363 /* This shouldn't happen */
1364 DPRINT1("Relocations failed!\n");
1365 while (TRUE);
1366 }
1367 }
1368
1369 /* Update the loader entry */
1370 LdrEntry->DllBase = NewImageAddress;
1371
1372 /* Update the thunks */
1373 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1374 MiUpdateThunks(LoaderBlock,
1375 DllBase,
1376 NewImageAddress,
1377 LdrEntry->SizeOfImage);
1378
1379 /* Update the loader entry */
1380 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
1381 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1382 NtHeader->OptionalHeader.AddressOfEntryPoint);
1383 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
1384
1385 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1386 }
1387 }
1388
1389 BOOLEAN
1390 NTAPI
1391 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1392 {
1393 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
1394 PLIST_ENTRY ListHead, NextEntry;
1395 ULONG EntrySize;
1396
1397 /* Setup the loaded module list and locks */
1398 ExInitializeResourceLite(&PsLoadedModuleResource);
1399 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
1400 InitializeListHead(&PsLoadedModuleList);
1401
1402 /* Get loop variables and the kernel entry */
1403 ListHead = &LoaderBlock->LoadOrderListHead;
1404 NextEntry = ListHead->Flink;
1405 LdrEntry = CONTAINING_RECORD(NextEntry,
1406 LDR_DATA_TABLE_ENTRY,
1407 InLoadOrderLinks);
1408 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
1409
1410 /* Loop the loader block */
1411 while (NextEntry != ListHead)
1412 {
1413 /* Get the loader entry */
1414 LdrEntry = CONTAINING_RECORD(NextEntry,
1415 LDR_DATA_TABLE_ENTRY,
1416 InLoadOrderLinks);
1417
1418 /* FIXME: ROS HACK. Make sure this is a driver */
1419 if (!RtlImageNtHeader(LdrEntry->DllBase))
1420 {
1421 /* Skip this entry */
1422 NextEntry= NextEntry->Flink;
1423 continue;
1424 }
1425
1426 /* Calculate the size we'll need and allocate a copy */
1427 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1428 LdrEntry->BaseDllName.MaximumLength +
1429 sizeof(UNICODE_NULL);
1430 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
1431 if (!NewEntry) return FALSE;
1432
1433 /* Copy the entry over */
1434 *NewEntry = *LdrEntry;
1435
1436 /* Allocate the name */
1437 NewEntry->FullDllName.Buffer =
1438 ExAllocatePoolWithTag(PagedPool,
1439 LdrEntry->FullDllName.MaximumLength +
1440 sizeof(UNICODE_NULL),
1441 TAG_LDR_WSTR);
1442 if (!NewEntry->FullDllName.Buffer) return FALSE;
1443
1444 /* Set the base name */
1445 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
1446
1447 /* Copy the full and base name */
1448 RtlCopyMemory(NewEntry->FullDllName.Buffer,
1449 LdrEntry->FullDllName.Buffer,
1450 LdrEntry->FullDllName.MaximumLength);
1451 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
1452 LdrEntry->BaseDllName.Buffer,
1453 LdrEntry->BaseDllName.MaximumLength);
1454
1455 /* Null-terminate the base name */
1456 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
1457 sizeof(WCHAR)] = UNICODE_NULL;
1458
1459 /* Insert the entry into the list */
1460 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
1461 NextEntry = NextEntry->Flink;
1462 }
1463
1464 /* Build the import lists for the boot drivers */
1465 //MiBuildImportsForBootDrivers();
1466
1467 /* We're done */
1468 return TRUE;
1469 }
1470
1471 BOOLEAN
1472 NTAPI
1473 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
1474 {
1475 PIMAGE_NT_HEADERS NtHeader;
1476 PAGED_CODE();
1477
1478 /* Get NT Headers */
1479 NtHeader = RtlImageNtHeader(BaseAddress);
1480 if (NtHeader)
1481 {
1482 /* Check if this image is only safe for UP while we have 2+ CPUs */
1483 if ((KeNumberProcessors > 1) &&
1484 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
1485 {
1486 /* Fail */
1487 return FALSE;
1488 }
1489 }
1490
1491 /* Otherwise, it's safe */
1492 return TRUE;
1493 }
1494
1495 NTSTATUS
1496 NTAPI
1497 MmCheckSystemImage(IN HANDLE ImageHandle,
1498 IN BOOLEAN PurgeSection)
1499 {
1500 NTSTATUS Status;
1501 HANDLE SectionHandle;
1502 PVOID ViewBase = NULL;
1503 SIZE_T ViewSize = 0;
1504 IO_STATUS_BLOCK IoStatusBlock;
1505 FILE_STANDARD_INFORMATION FileStandardInfo;
1506 KAPC_STATE ApcState;
1507 PAGED_CODE();
1508
1509 /* Create a section for the DLL */
1510 Status = ZwCreateSection(&SectionHandle,
1511 SECTION_MAP_EXECUTE,
1512 NULL,
1513 NULL,
1514 PAGE_EXECUTE,
1515 SEC_COMMIT,
1516 ImageHandle);
1517 if (!NT_SUCCESS(Status)) return Status;
1518
1519 /* Make sure we're in the system process */
1520 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1521
1522 /* Map it */
1523 Status = ZwMapViewOfSection(SectionHandle,
1524 NtCurrentProcess(),
1525 &ViewBase,
1526 0,
1527 0,
1528 NULL,
1529 &ViewSize,
1530 ViewShare,
1531 0,
1532 PAGE_EXECUTE);
1533 if (!NT_SUCCESS(Status))
1534 {
1535 /* We failed, close the handle and return */
1536 KeUnstackDetachProcess(&ApcState);
1537 ZwClose(SectionHandle);
1538 return Status;
1539 }
1540
1541 /* Now query image information */
1542 Status = ZwQueryInformationFile(ImageHandle,
1543 &IoStatusBlock,
1544 &FileStandardInfo,
1545 sizeof(FileStandardInfo),
1546 FileStandardInformation);
1547 if ( NT_SUCCESS(Status) )
1548 {
1549 /* First, verify the checksum */
1550 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
1551 FileStandardInfo.
1552 EndOfFile.LowPart,
1553 FileStandardInfo.
1554 EndOfFile.LowPart))
1555 {
1556 /* Set checksum failure */
1557 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
1558 }
1559
1560 /* Check that it's a valid SMP image if we have more then one CPU */
1561 if (!MmVerifyImageIsOkForMpUse(ViewBase))
1562 {
1563 /* Otherwise it's not the right image */
1564 Status = STATUS_IMAGE_MP_UP_MISMATCH;
1565 }
1566 }
1567
1568 /* Unmap the section, close the handle, and return status */
1569 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1570 KeUnstackDetachProcess(&ApcState);
1571 ZwClose(SectionHandle);
1572 return Status;
1573 }
1574
1575 NTSTATUS
1576 NTAPI
1577 MmLoadSystemImage(IN PUNICODE_STRING FileName,
1578 IN PUNICODE_STRING NamePrefix OPTIONAL,
1579 IN PUNICODE_STRING LoadedName OPTIONAL,
1580 IN ULONG Flags,
1581 OUT PVOID *ModuleObject,
1582 OUT PVOID *ImageBaseAddress)
1583 {
1584 PVOID ModuleLoadBase = NULL;
1585 NTSTATUS Status;
1586 HANDLE FileHandle = NULL;
1587 OBJECT_ATTRIBUTES ObjectAttributes;
1588 IO_STATUS_BLOCK IoStatusBlock;
1589 PIMAGE_NT_HEADERS NtHeader;
1590 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
1591 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
1592 ULONG EntrySize, DriverSize;
1593 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
1594 PCHAR MissingApiName, Buffer;
1595 PWCHAR MissingDriverName;
1596 HANDLE SectionHandle;
1597 ACCESS_MASK DesiredAccess;
1598 PVOID Section = NULL;
1599 BOOLEAN LockOwned = FALSE;
1600 PLIST_ENTRY NextEntry;
1601 IMAGE_INFO ImageInfo;
1602 STRING AnsiTemp;
1603 PAGED_CODE();
1604
1605 /* Detect session-load */
1606 if (Flags)
1607 {
1608 /* Sanity checks */
1609 ASSERT(NamePrefix == NULL);
1610 ASSERT(LoadedName == NULL);
1611
1612 /* Make sure the process is in session too */
1613 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
1614 }
1615
1616 /* Allocate a buffer we'll use for names */
1617 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
1618 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1619
1620 /* Check for a separator */
1621 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
1622 {
1623 PWCHAR p;
1624 ULONG BaseLength;
1625
1626 /* Loop the path until we get to the base name */
1627 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
1628 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
1629
1630 /* Get the length */
1631 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
1632 BaseLength *= sizeof(WCHAR);
1633
1634 /* Setup the string */
1635 BaseName.Length = (USHORT)BaseLength;
1636 BaseName.Buffer = p;
1637 }
1638 else
1639 {
1640 /* Otherwise, we already have a base name */
1641 BaseName.Length = FileName->Length;
1642 BaseName.Buffer = FileName->Buffer;
1643 }
1644
1645 /* Setup the maximum length */
1646 BaseName.MaximumLength = BaseName.Length;
1647
1648 /* Now compute the base directory */
1649 BaseDirectory = *FileName;
1650 BaseDirectory.Length -= BaseName.Length;
1651 BaseDirectory.MaximumLength = BaseDirectory.Length;
1652
1653 /* And the prefix, which for now is just the name itself */
1654 PrefixName = *FileName;
1655
1656 /* Check if we have a prefix */
1657 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
1658
1659 /* Check if we already have a name, use it instead */
1660 if (LoadedName) BaseName = *LoadedName;
1661
1662 /* Acquire the load lock */
1663 LoaderScan:
1664 ASSERT(LockOwned == FALSE);
1665 LockOwned = TRUE;
1666 KeEnterCriticalRegion();
1667 KeWaitForSingleObject(&MmSystemLoadLock,
1668 WrVirtualMemory,
1669 KernelMode,
1670 FALSE,
1671 NULL);
1672
1673 /* Scan the module list */
1674 NextEntry = PsLoadedModuleList.Flink;
1675 while (NextEntry != &PsLoadedModuleList)
1676 {
1677 /* Get the entry and compare the names */
1678 LdrEntry = CONTAINING_RECORD(NextEntry,
1679 LDR_DATA_TABLE_ENTRY,
1680 InLoadOrderLinks);
1681 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
1682 {
1683 /* Found it, break out */
1684 break;
1685 }
1686
1687 /* Keep scanning */
1688 NextEntry = NextEntry->Flink;
1689 }
1690
1691 /* Check if we found the image */
1692 if (NextEntry != &PsLoadedModuleList)
1693 {
1694 /* Check if we had already mapped a section */
1695 if (Section)
1696 {
1697 /* Dereference and clear */
1698 ObDereferenceObject(Section);
1699 Section = NULL;
1700 }
1701
1702 /* Check if this was supposed to be a session load */
1703 if (!Flags)
1704 {
1705 /* It wasn't, so just return the data */
1706 *ModuleObject = LdrEntry;
1707 *ImageBaseAddress = LdrEntry->DllBase;
1708 Status = STATUS_IMAGE_ALREADY_LOADED;
1709 }
1710 else
1711 {
1712 /* We don't support session loading yet */
1713 DPRINT1("Unsupported Session-Load!\n");
1714 while (TRUE);
1715 }
1716
1717 /* Do cleanup */
1718 goto Quickie;
1719 }
1720 else if (!Section)
1721 {
1722 /* It wasn't loaded, and we didn't have a previous attempt */
1723 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
1724 KeLeaveCriticalRegion();
1725 LockOwned = FALSE;
1726
1727 /* Check if KD is enabled */
1728 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
1729 {
1730 /* FIXME: Attempt to get image from KD */
1731 }
1732
1733 /* We don't have a valid entry */
1734 LdrEntry = NULL;
1735
1736 /* Setup image attributes */
1737 InitializeObjectAttributes(&ObjectAttributes,
1738 FileName,
1739 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1740 NULL,
1741 NULL);
1742
1743 /* Open the image */
1744 Status = ZwOpenFile(&FileHandle,
1745 FILE_EXECUTE,
1746 &ObjectAttributes,
1747 &IoStatusBlock,
1748 FILE_SHARE_READ | FILE_SHARE_DELETE,
1749 0);
1750 if (!NT_SUCCESS(Status)) goto Quickie;
1751
1752 /* Validate it */
1753 Status = MmCheckSystemImage(FileHandle, FALSE);
1754 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
1755 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
1756 (Status == STATUS_INVALID_IMAGE_FORMAT))
1757 {
1758 /* Fail loading */
1759 goto Quickie;
1760 }
1761
1762 /* Check if this is a session-load */
1763 if (Flags)
1764 {
1765 /* Then we only need read and execute */
1766 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
1767 }
1768 else
1769 {
1770 /* Otherwise, we can allow write access */
1771 DesiredAccess = SECTION_ALL_ACCESS;
1772 }
1773
1774 /* Initialize the attributes for the section */
1775 InitializeObjectAttributes(&ObjectAttributes,
1776 NULL,
1777 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1778 NULL,
1779 NULL);
1780
1781 /* Create the section */
1782 Status = ZwCreateSection(&SectionHandle,
1783 DesiredAccess,
1784 &ObjectAttributes,
1785 NULL,
1786 PAGE_EXECUTE,
1787 SEC_IMAGE,
1788 FileHandle);
1789 if (!NT_SUCCESS(Status)) goto Quickie;
1790
1791 /* Now get the section pointer */
1792 Status = ObReferenceObjectByHandle(SectionHandle,
1793 SECTION_MAP_EXECUTE,
1794 MmSectionObjectType,
1795 KernelMode,
1796 &Section,
1797 NULL);
1798 ZwClose(SectionHandle);
1799 if (!NT_SUCCESS(Status)) goto Quickie;
1800
1801 /* Check if this was supposed to be a session-load */
1802 if (Flags)
1803 {
1804 /* We don't support session loading yet */
1805 DPRINT1("Unsupported Session-Load!\n");
1806 while (TRUE);
1807 }
1808
1809 /* Check the loader list again, we should end up in the path below */
1810 goto LoaderScan;
1811 }
1812 else
1813 {
1814 /* We don't have a valid entry */
1815 LdrEntry = NULL;
1816 }
1817
1818 /* Load the image */
1819 Status = MiLoadImageSection(&Section,
1820 &ModuleLoadBase,
1821 FileName,
1822 FALSE,
1823 NULL);
1824 ASSERT(Status != STATUS_ALREADY_COMMITTED);
1825
1826 /* Get the size of the driver */
1827 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
1828
1829 /* Make sure we're not being loaded into session space */
1830 if (!Flags)
1831 {
1832 /* Check for success */
1833 if (NT_SUCCESS(Status))
1834 {
1835 /* FIXME: Support large pages for drivers */
1836 }
1837
1838 /* Dereference the section */
1839 ObDereferenceObject(Section);
1840 Section = NULL;
1841 }
1842
1843 /* Get the NT Header */
1844 NtHeader = RtlImageNtHeader(ModuleLoadBase);
1845
1846 /* Relocate the driver */
1847 Status = LdrRelocateImageWithBias(ModuleLoadBase,
1848 0,
1849 "SYSLDR",
1850 STATUS_SUCCESS,
1851 STATUS_CONFLICTING_ADDRESSES,
1852 STATUS_INVALID_IMAGE_FORMAT);
1853 if (!NT_SUCCESS(Status)) goto Quickie;
1854
1855 /* Calculate the size we'll need for the entry and allocate it */
1856 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1857 BaseName.Length +
1858 sizeof(UNICODE_NULL);
1859
1860 /* Allocate the entry */
1861 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
1862 if (!LdrEntry)
1863 {
1864 /* Fail */
1865 Status = STATUS_INSUFFICIENT_RESOURCES;
1866 goto Quickie;
1867 }
1868
1869 /* Setup the entry */
1870 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
1871 LdrEntry->LoadCount = 1;
1872 LdrEntry->LoadedImports = LoadedImports;
1873 LdrEntry->PatchInformation = NULL;
1874
1875 /* Check the version */
1876 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
1877 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
1878 {
1879 /* Mark this image as a native image */
1880 LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
1881 }
1882
1883 /* Setup the rest of the entry */
1884 LdrEntry->DllBase = ModuleLoadBase;
1885 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
1886 NtHeader->OptionalHeader.AddressOfEntryPoint);
1887 LdrEntry->SizeOfImage = DriverSize;
1888 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
1889 LdrEntry->SectionPointer = Section;
1890
1891 /* Now write the DLL name */
1892 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
1893 LdrEntry->BaseDllName.Length = BaseName.Length;
1894 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
1895
1896 /* Copy and null-terminate it */
1897 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
1898 BaseName.Buffer,
1899 BaseName.Length);
1900 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1901
1902 /* Now allocate the full name */
1903 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
1904 PrefixName.Length +
1905 sizeof(UNICODE_NULL),
1906 TAG_LDR_WSTR);
1907 if (!LdrEntry->FullDllName.Buffer)
1908 {
1909 /* Don't fail, just set it to zero */
1910 LdrEntry->FullDllName.Length = 0;
1911 LdrEntry->FullDllName.MaximumLength = 0;
1912 }
1913 else
1914 {
1915 /* Set it up */
1916 LdrEntry->FullDllName.Length = PrefixName.Length;
1917 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
1918
1919 /* Copy and null-terminate */
1920 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
1921 PrefixName.Buffer,
1922 PrefixName.Length);
1923 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1924 }
1925
1926 /* Add the entry */
1927 MiProcessLoaderEntry(LdrEntry, TRUE);
1928
1929 /* Resolve imports */
1930 MissingApiName = Buffer;
1931 Status = MiResolveImageReferences(ModuleLoadBase,
1932 &BaseDirectory,
1933 NULL,
1934 &MissingApiName,
1935 &MissingDriverName,
1936 &LoadedImports);
1937 if (!NT_SUCCESS(Status))
1938 {
1939 /* Fail */
1940 MiProcessLoaderEntry(LdrEntry, FALSE);
1941
1942 /* Check if we need to free the name */
1943 if (LdrEntry->FullDllName.Buffer)
1944 {
1945 /* Free it */
1946 ExFreePool(LdrEntry->FullDllName.Buffer);
1947 }
1948
1949 /* Free the entry itself */
1950 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
1951 LdrEntry = NULL;
1952 goto Quickie;
1953 }
1954
1955 /* Update the loader entry */
1956 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
1957 LDRP_ENTRY_PROCESSED |
1958 LDRP_MM_LOADED);
1959 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
1960 LdrEntry->LoadedImports = LoadedImports;
1961
1962 /* FIXME: Apply driver verifier */
1963
1964 /* FIXME: Write-protect the system image */
1965
1966 /* Check if notifications are enabled */
1967 if (PsImageNotifyEnabled)
1968 {
1969 /* Fill out the notification data */
1970 ImageInfo.Properties = 0;
1971 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
1972 ImageInfo.SystemModeImage = TRUE;
1973 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
1974 ImageInfo.ImageBase = LdrEntry->DllBase;
1975 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
1976
1977 /* Send the notification */
1978 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
1979 }
1980
1981 #if defined(KDBG) || defined(_WINKD_)
1982 /* MiCacheImageSymbols doesn't detect rossym */
1983 if (TRUE)
1984 #else
1985 /* Check if there's symbols */
1986 if (MiCacheImageSymbols(LdrEntry->DllBase))
1987 #endif
1988 {
1989 /* Check if the system root is present */
1990 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
1991 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
1992 {
1993 /* Add the system root */
1994 UnicodeTemp = PrefixName;
1995 UnicodeTemp.Buffer += 11;
1996 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
1997 sprintf_nt(Buffer,
1998 "%ws%wZ",
1999 &SharedUserData->NtSystemRoot[2],
2000 &UnicodeTemp);
2001 }
2002 else
2003 {
2004 /* Build the name */
2005 sprintf_nt(Buffer, "%wZ", &BaseName);
2006 }
2007
2008 /* Setup the ansi string */
2009 RtlInitString(&AnsiTemp, Buffer);
2010
2011 /* Notify the debugger */
2012 DbgLoadImageSymbols(&AnsiTemp,
2013 LdrEntry->DllBase,
2014 (ULONG_PTR)ZwCurrentProcess());
2015 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
2016 }
2017
2018 /* FIXME: Page the driver */
2019 ASSERT(Section == NULL);
2020
2021 /* Return pointers */
2022 *ModuleObject = LdrEntry;
2023 *ImageBaseAddress = LdrEntry->DllBase;
2024
2025 Quickie:
2026 /* If we have a file handle, close it */
2027 if (FileHandle) ZwClose(FileHandle);
2028
2029 /* Check if we have the lock acquired */
2030 if (LockOwned)
2031 {
2032 /* Release the lock */
2033 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
2034 KeLeaveCriticalRegion();
2035 LockOwned = FALSE;
2036 }
2037
2038 /* Check if we had a prefix */
2039 if (NamePrefix) ExFreePool(PrefixName.Buffer);
2040
2041 /* Free the name buffer and return status */
2042 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
2043 return Status;
2044 }
2045
2046 PLDR_DATA_TABLE_ENTRY
2047 NTAPI
2048 MiLookupDataTableEntry(IN PVOID Address)
2049 {
2050 PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL;
2051 PLIST_ENTRY NextEntry;
2052 PAGED_CODE();
2053
2054 /* Loop entries */
2055 NextEntry = PsLoadedModuleList.Flink;
2056 do
2057 {
2058 /* Get the loader entry */
2059 LdrEntry = CONTAINING_RECORD(NextEntry,
2060 LDR_DATA_TABLE_ENTRY,
2061 InLoadOrderLinks);
2062
2063 /* Check if the address matches */
2064 if ((Address >= LdrEntry->DllBase) &&
2065 (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase +
2066 LdrEntry->SizeOfImage)))
2067 {
2068 /* Found a match */
2069 FoundEntry = LdrEntry;
2070 break;
2071 }
2072
2073 /* Move on */
2074 NextEntry = NextEntry->Flink;
2075 } while(NextEntry != &PsLoadedModuleList);
2076
2077 /* Return the entry */
2078 return FoundEntry;
2079 }
2080
2081 /*
2082 * @implemented
2083 */
2084 PVOID
2085 NTAPI
2086 MmPageEntireDriver(IN PVOID AddressWithinSection)
2087 {
2088 PMMPTE StartPte, EndPte;
2089 PLDR_DATA_TABLE_ENTRY LdrEntry;
2090 PAGED_CODE();
2091
2092 /* Get the loader entry */
2093 LdrEntry = MiLookupDataTableEntry(AddressWithinSection);
2094 if (!LdrEntry) return NULL;
2095
2096 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
2097 if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer))
2098 {
2099 /* Don't do anything, just return the base address */
2100 return LdrEntry->DllBase;
2101 }
2102
2103 /* Wait for active DPCs to finish before we page out the driver */
2104 KeFlushQueuedDpcs();
2105
2106 /* Get the PTE range for the whole driver image */
2107 StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase);
2108 EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);
2109 #if 0
2110 /* Enable paging for the PTE range */
2111 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE);
2112 MiSetPagingOfDriver(StartPte, EndPte);
2113 #endif
2114 /* Return the base address */
2115 return LdrEntry->DllBase;
2116 }
2117
2118 /*
2119 * @unimplemented
2120 */
2121 VOID
2122 NTAPI
2123 MmResetDriverPaging(IN PVOID AddressWithinSection)
2124 {
2125 UNIMPLEMENTED;
2126 }
2127 /*
2128 * @implemented
2129 */
2130 PVOID
2131 NTAPI
2132 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
2133 {
2134 PVOID ProcAddress = NULL;
2135 ANSI_STRING AnsiRoutineName;
2136 NTSTATUS Status;
2137 PLIST_ENTRY NextEntry;
2138 PLDR_DATA_TABLE_ENTRY LdrEntry;
2139 BOOLEAN Found = FALSE;
2140 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
2141 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
2142 ULONG Modules = 0;
2143
2144 /* Convert routine to ansi name */
2145 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
2146 SystemRoutineName,
2147 TRUE);
2148 if (!NT_SUCCESS(Status)) return NULL;
2149
2150 /* Lock the list */
2151 KeEnterCriticalRegion();
2152 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
2153
2154 /* Loop the loaded module list */
2155 NextEntry = PsLoadedModuleList.Flink;
2156 while (NextEntry != &PsLoadedModuleList)
2157 {
2158 /* Get the entry */
2159 LdrEntry = CONTAINING_RECORD(NextEntry,
2160 LDR_DATA_TABLE_ENTRY,
2161 InLoadOrderLinks);
2162
2163 /* Check if it's the kernel or HAL */
2164 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
2165 {
2166 /* Found it */
2167 Found = TRUE;
2168 Modules++;
2169 }
2170 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
2171 {
2172 /* Found it */
2173 Found = TRUE;
2174 Modules++;
2175 }
2176
2177 /* Check if we found a valid binary */
2178 if (Found)
2179 {
2180 /* Find the procedure name */
2181 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
2182 &AnsiRoutineName);
2183
2184 /* Break out if we found it or if we already tried both modules */
2185 if (ProcAddress) break;
2186 if (Modules == 2) break;
2187 }
2188
2189 /* Keep looping */
2190 NextEntry = NextEntry->Flink;
2191 }
2192
2193 /* Release the lock */
2194 ExReleaseResourceLite(&PsLoadedModuleResource);
2195 KeLeaveCriticalRegion();
2196
2197 /* Free the string and return */
2198 RtlFreeAnsiString(&AnsiRoutineName);
2199 return ProcAddress;
2200 }
2201