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