Sync with trunk head
[reactos.git] / 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 /* FIXME: 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;
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 /* Loop driver list */
1228 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1229 NextEntry != &LoaderBlock->LoadOrderListHead;
1230 NextEntry = NextEntry->Flink)
1231 {
1232 /* Get the loader entry and NT header */
1233 LdrEntry = CONTAINING_RECORD(NextEntry,
1234 LDR_DATA_TABLE_ENTRY,
1235 InLoadOrderLinks);
1236 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1237
1238 /* Debug info */
1239 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1240 LdrEntry->DllBase,
1241 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
1242 &LdrEntry->FullDllName);
1243
1244 /* Skip kernel and HAL */
1245 /* ROS HACK: Skip BOOTVID/KDCOM too */
1246 i++;
1247 if (i <= 4) continue;
1248
1249 /* Skip non-drivers */
1250 if (!NtHeader) continue;
1251
1252 /* Get the file header and make sure we can relocate */
1253 FileHeader = &NtHeader->FileHeader;
1254 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1255 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1256 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1257
1258 /* Everything made sense until now, check the relocation section too */
1259 DataDirectory = &NtHeader->OptionalHeader.
1260 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1261 if (!DataDirectory->VirtualAddress)
1262 {
1263 /* We don't really have relocations */
1264 ValidRelocs = FALSE;
1265 }
1266 else
1267 {
1268 /* Make sure the size is valid */
1269 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1270 LdrEntry->SizeOfImage)
1271 {
1272 /* They're not, skip */
1273 continue;
1274 }
1275
1276 /* We have relocations */
1277 ValidRelocs = TRUE;
1278 }
1279
1280 /* Remember the original address */
1281 DllBase = LdrEntry->DllBase;
1282
1283 /* Get the first PTE and the number of PTEs we'll need */
1284 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
1285 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
1286 LastPte = StartPte + PteCount;
1287
1288 /* Loop the PTEs */
1289 while (PointerPte < LastPte)
1290 {
1291 /* Mark the page modified in the PFN database */
1292 ASSERT(PointerPte->u.Hard.Valid == 1);
1293 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1294 ASSERT(Pfn1->u3.e1.Rom == 0);
1295 Pfn1->u3.e1.Modified = TRUE;
1296
1297 /* Next */
1298 PointerPte++;
1299 }
1300
1301 /* Now reserve system PTEs for the image */
1302 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
1303 if (!PointerPte)
1304 {
1305 /* Shouldn't happen */
1306 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1307 while (TRUE);
1308 }
1309
1310 /* This is the new virtual address for the module */
1311 LastPte = PointerPte + PteCount;
1312 NewImageAddress = MiPteToAddress(PointerPte);
1313
1314 /* Sanity check */
1315 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1316 ASSERT(ExpInitializationPhase == 0);
1317
1318 /* Loop the new driver PTEs */
1319 TempPte = ValidKernelPte;
1320 while (PointerPte < LastPte)
1321 {
1322 /* Copy the old data */
1323 OldPte = *StartPte;
1324 ASSERT(OldPte.u.Hard.Valid == 1);
1325
1326 /* Set page number from the loader's memory */
1327 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
1328
1329 /* Write it */
1330 ASSERT(PointerPte->u.Hard.Valid == 0);
1331 ASSERT(TempPte.u.Hard.Valid == 1);
1332 *PointerPte = TempPte;
1333
1334 /* Move on */
1335 PointerPte++;
1336 StartPte++;
1337 }
1338
1339 /* Update position */
1340 PointerPte -= PteCount;
1341
1342 /* Sanity check */
1343 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1344
1345 /* Set the image base to the address where the loader put it */
1346 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1347
1348 /* Check if we had relocations */
1349 if (ValidRelocs)
1350 {
1351 /* Relocate the image */
1352 Status = LdrRelocateImageWithBias(NewImageAddress,
1353 0,
1354 "SYSLDR",
1355 STATUS_SUCCESS,
1356 STATUS_CONFLICTING_ADDRESSES,
1357 STATUS_INVALID_IMAGE_FORMAT);
1358 if (!NT_SUCCESS(Status))
1359 {
1360 /* This shouldn't happen */
1361 DPRINT1("Relocations failed!\n");
1362 while (TRUE);
1363 }
1364 }
1365
1366 /* Update the loader entry */
1367 LdrEntry->DllBase = NewImageAddress;
1368
1369 /* Update the thunks */
1370 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1371 MiUpdateThunks(LoaderBlock,
1372 DllBase,
1373 NewImageAddress,
1374 LdrEntry->SizeOfImage);
1375
1376 /* Update the loader entry */
1377 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
1378 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1379 NtHeader->OptionalHeader.AddressOfEntryPoint);
1380 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
1381
1382 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1383 }
1384 }
1385
1386 BOOLEAN
1387 NTAPI
1388 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1389 {
1390 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
1391 PLIST_ENTRY ListHead, NextEntry;
1392 ULONG EntrySize;
1393
1394 /* Setup the loaded module list and locks */
1395 ExInitializeResourceLite(&PsLoadedModuleResource);
1396 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
1397 InitializeListHead(&PsLoadedModuleList);
1398
1399 /* Get loop variables and the kernel entry */
1400 ListHead = &LoaderBlock->LoadOrderListHead;
1401 NextEntry = ListHead->Flink;
1402 LdrEntry = CONTAINING_RECORD(NextEntry,
1403 LDR_DATA_TABLE_ENTRY,
1404 InLoadOrderLinks);
1405 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
1406
1407 /* Loop the loader block */
1408 while (NextEntry != ListHead)
1409 {
1410 /* Get the loader entry */
1411 LdrEntry = CONTAINING_RECORD(NextEntry,
1412 LDR_DATA_TABLE_ENTRY,
1413 InLoadOrderLinks);
1414
1415 /* FIXME: ROS HACK. Make sure this is a driver */
1416 if (!RtlImageNtHeader(LdrEntry->DllBase))
1417 {
1418 /* Skip this entry */
1419 NextEntry= NextEntry->Flink;
1420 continue;
1421 }
1422
1423 /* Calculate the size we'll need and allocate a copy */
1424 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1425 LdrEntry->BaseDllName.MaximumLength +
1426 sizeof(UNICODE_NULL);
1427 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
1428 if (!NewEntry) return FALSE;
1429
1430 /* Copy the entry over */
1431 *NewEntry = *LdrEntry;
1432
1433 /* Allocate the name */
1434 NewEntry->FullDllName.Buffer =
1435 ExAllocatePoolWithTag(PagedPool,
1436 LdrEntry->FullDllName.MaximumLength +
1437 sizeof(UNICODE_NULL),
1438 TAG_LDR_WSTR);
1439 if (!NewEntry->FullDllName.Buffer) return FALSE;
1440
1441 /* Set the base name */
1442 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
1443
1444 /* Copy the full and base name */
1445 RtlCopyMemory(NewEntry->FullDllName.Buffer,
1446 LdrEntry->FullDllName.Buffer,
1447 LdrEntry->FullDllName.MaximumLength);
1448 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
1449 LdrEntry->BaseDllName.Buffer,
1450 LdrEntry->BaseDllName.MaximumLength);
1451
1452 /* Null-terminate the base name */
1453 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
1454 sizeof(WCHAR)] = UNICODE_NULL;
1455
1456 /* Insert the entry into the list */
1457 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
1458 NextEntry = NextEntry->Flink;
1459 }
1460
1461 /* Build the import lists for the boot drivers */
1462 //MiBuildImportsForBootDrivers();
1463
1464 /* We're done */
1465 return TRUE;
1466 }
1467
1468 BOOLEAN
1469 NTAPI
1470 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
1471 {
1472 PIMAGE_NT_HEADERS NtHeader;
1473 PAGED_CODE();
1474
1475 /* Get NT Headers */
1476 NtHeader = RtlImageNtHeader(BaseAddress);
1477 if (NtHeader)
1478 {
1479 /* Check if this image is only safe for UP while we have 2+ CPUs */
1480 if ((KeNumberProcessors > 1) &&
1481 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
1482 {
1483 /* Fail */
1484 return FALSE;
1485 }
1486 }
1487
1488 /* Otherwise, it's safe */
1489 return TRUE;
1490 }
1491
1492 NTSTATUS
1493 NTAPI
1494 MmCheckSystemImage(IN HANDLE ImageHandle,
1495 IN BOOLEAN PurgeSection)
1496 {
1497 NTSTATUS Status;
1498 HANDLE SectionHandle;
1499 PVOID ViewBase = NULL;
1500 SIZE_T ViewSize = 0;
1501 IO_STATUS_BLOCK IoStatusBlock;
1502 FILE_STANDARD_INFORMATION FileStandardInfo;
1503 KAPC_STATE ApcState;
1504 PAGED_CODE();
1505
1506 /* Create a section for the DLL */
1507 Status = ZwCreateSection(&SectionHandle,
1508 SECTION_MAP_EXECUTE,
1509 NULL,
1510 NULL,
1511 PAGE_EXECUTE,
1512 SEC_COMMIT,
1513 ImageHandle);
1514 if (!NT_SUCCESS(Status)) return Status;
1515
1516 /* Make sure we're in the system process */
1517 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1518
1519 /* Map it */
1520 Status = ZwMapViewOfSection(SectionHandle,
1521 NtCurrentProcess(),
1522 &ViewBase,
1523 0,
1524 0,
1525 NULL,
1526 &ViewSize,
1527 ViewShare,
1528 0,
1529 PAGE_EXECUTE);
1530 if (!NT_SUCCESS(Status))
1531 {
1532 /* We failed, close the handle and return */
1533 KeUnstackDetachProcess(&ApcState);
1534 ZwClose(SectionHandle);
1535 return Status;
1536 }
1537
1538 /* Now query image information */
1539 Status = ZwQueryInformationFile(ImageHandle,
1540 &IoStatusBlock,
1541 &FileStandardInfo,
1542 sizeof(FileStandardInfo),
1543 FileStandardInformation);
1544 if ( NT_SUCCESS(Status) )
1545 {
1546 /* First, verify the checksum */
1547 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
1548 FileStandardInfo.
1549 EndOfFile.LowPart,
1550 FileStandardInfo.
1551 EndOfFile.LowPart))
1552 {
1553 /* Set checksum failure */
1554 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
1555 }
1556
1557 /* Check that it's a valid SMP image if we have more then one CPU */
1558 if (!MmVerifyImageIsOkForMpUse(ViewBase))
1559 {
1560 /* Otherwise it's not the right image */
1561 Status = STATUS_IMAGE_MP_UP_MISMATCH;
1562 }
1563 }
1564
1565 /* Unmap the section, close the handle, and return status */
1566 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1567 KeUnstackDetachProcess(&ApcState);
1568 ZwClose(SectionHandle);
1569 return Status;
1570 }
1571
1572 NTSTATUS
1573 NTAPI
1574 MmLoadSystemImage(IN PUNICODE_STRING FileName,
1575 IN PUNICODE_STRING NamePrefix OPTIONAL,
1576 IN PUNICODE_STRING LoadedName OPTIONAL,
1577 IN ULONG Flags,
1578 OUT PVOID *ModuleObject,
1579 OUT PVOID *ImageBaseAddress)
1580 {
1581 PVOID ModuleLoadBase = NULL;
1582 NTSTATUS Status;
1583 HANDLE FileHandle = NULL;
1584 OBJECT_ATTRIBUTES ObjectAttributes;
1585 IO_STATUS_BLOCK IoStatusBlock;
1586 PIMAGE_NT_HEADERS NtHeader;
1587 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
1588 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
1589 ULONG EntrySize, DriverSize;
1590 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
1591 PCHAR MissingApiName, Buffer;
1592 PWCHAR MissingDriverName;
1593 HANDLE SectionHandle;
1594 ACCESS_MASK DesiredAccess;
1595 PVOID Section = NULL;
1596 BOOLEAN LockOwned = FALSE;
1597 PLIST_ENTRY NextEntry;
1598 IMAGE_INFO ImageInfo;
1599 STRING AnsiTemp;
1600 PAGED_CODE();
1601
1602 /* Detect session-load */
1603 if (Flags)
1604 {
1605 /* Sanity checks */
1606 ASSERT(NamePrefix == NULL);
1607 ASSERT(LoadedName == NULL);
1608
1609 /* Make sure the process is in session too */
1610 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
1611 }
1612
1613 /* Allocate a buffer we'll use for names */
1614 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
1615 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1616
1617 /* Check for a separator */
1618 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
1619 {
1620 PWCHAR p;
1621 ULONG BaseLength;
1622
1623 /* Loop the path until we get to the base name */
1624 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
1625 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
1626
1627 /* Get the length */
1628 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
1629 BaseLength *= sizeof(WCHAR);
1630
1631 /* Setup the string */
1632 BaseName.Length = (USHORT)BaseLength;
1633 BaseName.Buffer = p;
1634 }
1635 else
1636 {
1637 /* Otherwise, we already have a base name */
1638 BaseName.Length = FileName->Length;
1639 BaseName.Buffer = FileName->Buffer;
1640 }
1641
1642 /* Setup the maximum length */
1643 BaseName.MaximumLength = BaseName.Length;
1644
1645 /* Now compute the base directory */
1646 BaseDirectory = *FileName;
1647 BaseDirectory.Length -= BaseName.Length;
1648 BaseDirectory.MaximumLength = BaseDirectory.Length;
1649
1650 /* And the prefix, which for now is just the name itself */
1651 PrefixName = *FileName;
1652
1653 /* Check if we have a prefix */
1654 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
1655
1656 /* Check if we already have a name, use it instead */
1657 if (LoadedName) BaseName = *LoadedName;
1658
1659 /* Acquire the load lock */
1660 LoaderScan:
1661 ASSERT(LockOwned == FALSE);
1662 LockOwned = TRUE;
1663 KeEnterCriticalRegion();
1664 KeWaitForSingleObject(&MmSystemLoadLock,
1665 WrVirtualMemory,
1666 KernelMode,
1667 FALSE,
1668 NULL);
1669
1670 /* Scan the module list */
1671 NextEntry = PsLoadedModuleList.Flink;
1672 while (NextEntry != &PsLoadedModuleList)
1673 {
1674 /* Get the entry and compare the names */
1675 LdrEntry = CONTAINING_RECORD(NextEntry,
1676 LDR_DATA_TABLE_ENTRY,
1677 InLoadOrderLinks);
1678 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
1679 {
1680 /* Found it, break out */
1681 break;
1682 }
1683
1684 /* Keep scanning */
1685 NextEntry = NextEntry->Flink;
1686 }
1687
1688 /* Check if we found the image */
1689 if (NextEntry != &PsLoadedModuleList)
1690 {
1691 /* Check if we had already mapped a section */
1692 if (Section)
1693 {
1694 /* Dereference and clear */
1695 ObDereferenceObject(Section);
1696 Section = NULL;
1697 }
1698
1699 /* Check if this was supposed to be a session load */
1700 if (!Flags)
1701 {
1702 /* It wasn't, so just return the data */
1703 *ModuleObject = LdrEntry;
1704 *ImageBaseAddress = LdrEntry->DllBase;
1705 Status = STATUS_IMAGE_ALREADY_LOADED;
1706 }
1707 else
1708 {
1709 /* We don't support session loading yet */
1710 DPRINT1("Unsupported Session-Load!\n");
1711 while (TRUE);
1712 }
1713
1714 /* Do cleanup */
1715 goto Quickie;
1716 }
1717 else if (!Section)
1718 {
1719 /* It wasn't loaded, and we didn't have a previous attempt */
1720 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
1721 KeLeaveCriticalRegion();
1722 LockOwned = FALSE;
1723
1724 /* Check if KD is enabled */
1725 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
1726 {
1727 /* FIXME: Attempt to get image from KD */
1728 }
1729
1730 /* We don't have a valid entry */
1731 LdrEntry = NULL;
1732
1733 /* Setup image attributes */
1734 InitializeObjectAttributes(&ObjectAttributes,
1735 FileName,
1736 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1737 NULL,
1738 NULL);
1739
1740 /* Open the image */
1741 Status = ZwOpenFile(&FileHandle,
1742 FILE_EXECUTE,
1743 &ObjectAttributes,
1744 &IoStatusBlock,
1745 FILE_SHARE_READ | FILE_SHARE_DELETE,
1746 0);
1747 if (!NT_SUCCESS(Status)) goto Quickie;
1748
1749 /* Validate it */
1750 Status = MmCheckSystemImage(FileHandle, FALSE);
1751 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
1752 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
1753 (Status == STATUS_INVALID_IMAGE_FORMAT))
1754 {
1755 /* Fail loading */
1756 goto Quickie;
1757 }
1758
1759 /* Check if this is a session-load */
1760 if (Flags)
1761 {
1762 /* Then we only need read and execute */
1763 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
1764 }
1765 else
1766 {
1767 /* Otherwise, we can allow write access */
1768 DesiredAccess = SECTION_ALL_ACCESS;
1769 }
1770
1771 /* Initialize the attributes for the section */
1772 InitializeObjectAttributes(&ObjectAttributes,
1773 NULL,
1774 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1775 NULL,
1776 NULL);
1777
1778 /* Create the section */
1779 Status = ZwCreateSection(&SectionHandle,
1780 DesiredAccess,
1781 &ObjectAttributes,
1782 NULL,
1783 PAGE_EXECUTE,
1784 SEC_IMAGE,
1785 FileHandle);
1786 if (!NT_SUCCESS(Status)) goto Quickie;
1787
1788 /* Now get the section pointer */
1789 Status = ObReferenceObjectByHandle(SectionHandle,
1790 SECTION_MAP_EXECUTE,
1791 MmSectionObjectType,
1792 KernelMode,
1793 &Section,
1794 NULL);
1795 ZwClose(SectionHandle);
1796 if (!NT_SUCCESS(Status)) goto Quickie;
1797
1798 /* Check if this was supposed to be a session-load */
1799 if (Flags)
1800 {
1801 /* We don't support session loading yet */
1802 DPRINT1("Unsupported Session-Load!\n");
1803 while (TRUE);
1804 }
1805
1806 /* Check the loader list again, we should end up in the path below */
1807 goto LoaderScan;
1808 }
1809 else
1810 {
1811 /* We don't have a valid entry */
1812 LdrEntry = NULL;
1813 }
1814
1815 /* Load the image */
1816 Status = MiLoadImageSection(&Section,
1817 &ModuleLoadBase,
1818 FileName,
1819 FALSE,
1820 NULL);
1821 ASSERT(Status != STATUS_ALREADY_COMMITTED);
1822
1823 /* Get the size of the driver */
1824 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
1825
1826 /* Make sure we're not being loaded into session space */
1827 if (!Flags)
1828 {
1829 /* Check for success */
1830 if (NT_SUCCESS(Status))
1831 {
1832 /* FIXME: Support large pages for drivers */
1833 }
1834
1835 /* Dereference the section */
1836 ObDereferenceObject(Section);
1837 Section = NULL;
1838 }
1839
1840 /* Get the NT Header */
1841 NtHeader = RtlImageNtHeader(ModuleLoadBase);
1842
1843 /* Relocate the driver */
1844 Status = LdrRelocateImageWithBias(ModuleLoadBase,
1845 0,
1846 "SYSLDR",
1847 STATUS_SUCCESS,
1848 STATUS_CONFLICTING_ADDRESSES,
1849 STATUS_INVALID_IMAGE_FORMAT);
1850 if (!NT_SUCCESS(Status)) goto Quickie;
1851
1852 /* Calculate the size we'll need for the entry and allocate it */
1853 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1854 BaseName.Length +
1855 sizeof(UNICODE_NULL);
1856
1857 /* Allocate the entry */
1858 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
1859 if (!LdrEntry)
1860 {
1861 /* Fail */
1862 Status = STATUS_INSUFFICIENT_RESOURCES;
1863 goto Quickie;
1864 }
1865
1866 /* Setup the entry */
1867 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
1868 LdrEntry->LoadCount = 1;
1869 LdrEntry->LoadedImports = LoadedImports;
1870 LdrEntry->PatchInformation = NULL;
1871
1872 /* Check the version */
1873 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
1874 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
1875 {
1876 /* Mark this image as a native image */
1877 LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
1878 }
1879
1880 /* Setup the rest of the entry */
1881 LdrEntry->DllBase = ModuleLoadBase;
1882 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
1883 NtHeader->OptionalHeader.AddressOfEntryPoint);
1884 LdrEntry->SizeOfImage = DriverSize;
1885 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
1886 LdrEntry->SectionPointer = Section;
1887
1888 /* Now write the DLL name */
1889 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
1890 LdrEntry->BaseDllName.Length = BaseName.Length;
1891 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
1892
1893 /* Copy and null-terminate it */
1894 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
1895 BaseName.Buffer,
1896 BaseName.Length);
1897 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1898
1899 /* Now allocate the full name */
1900 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
1901 PrefixName.Length +
1902 sizeof(UNICODE_NULL),
1903 TAG_LDR_WSTR);
1904 if (!LdrEntry->FullDllName.Buffer)
1905 {
1906 /* Don't fail, just set it to zero */
1907 LdrEntry->FullDllName.Length = 0;
1908 LdrEntry->FullDllName.MaximumLength = 0;
1909 }
1910 else
1911 {
1912 /* Set it up */
1913 LdrEntry->FullDllName.Length = PrefixName.Length;
1914 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
1915
1916 /* Copy and null-terminate */
1917 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
1918 PrefixName.Buffer,
1919 PrefixName.Length);
1920 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1921 }
1922
1923 /* Add the entry */
1924 MiProcessLoaderEntry(LdrEntry, TRUE);
1925
1926 /* Resolve imports */
1927 MissingApiName = Buffer;
1928 Status = MiResolveImageReferences(ModuleLoadBase,
1929 &BaseDirectory,
1930 NULL,
1931 &MissingApiName,
1932 &MissingDriverName,
1933 &LoadedImports);
1934 if (!NT_SUCCESS(Status))
1935 {
1936 /* Fail */
1937 MiProcessLoaderEntry(LdrEntry, FALSE);
1938
1939 /* Check if we need to free the name */
1940 if (LdrEntry->FullDllName.Buffer)
1941 {
1942 /* Free it */
1943 ExFreePool(LdrEntry->FullDllName.Buffer);
1944 }
1945
1946 /* Free the entry itself */
1947 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
1948 LdrEntry = NULL;
1949 goto Quickie;
1950 }
1951
1952 /* Update the loader entry */
1953 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
1954 LDRP_ENTRY_PROCESSED |
1955 LDRP_MM_LOADED);
1956 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
1957 LdrEntry->LoadedImports = LoadedImports;
1958
1959 /* FIXME: Apply driver verifier */
1960
1961 /* FIXME: Write-protect the system image */
1962
1963 /* Check if notifications are enabled */
1964 if (PsImageNotifyEnabled)
1965 {
1966 /* Fill out the notification data */
1967 ImageInfo.Properties = 0;
1968 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
1969 ImageInfo.SystemModeImage = TRUE;
1970 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
1971 ImageInfo.ImageBase = LdrEntry->DllBase;
1972 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
1973
1974 /* Send the notification */
1975 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
1976 }
1977
1978 #if defined(KDBG) || defined(_WINKD_)
1979 /* MiCacheImageSymbols doesn't detect rossym */
1980 if (TRUE)
1981 #else
1982 /* Check if there's symbols */
1983 if (MiCacheImageSymbols(LdrEntry->DllBase))
1984 #endif
1985 {
1986 /* Check if the system root is present */
1987 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
1988 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
1989 {
1990 /* Add the system root */
1991 UnicodeTemp = PrefixName;
1992 UnicodeTemp.Buffer += 11;
1993 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
1994 sprintf_nt(Buffer,
1995 "%ws%wZ",
1996 &SharedUserData->NtSystemRoot[2],
1997 &UnicodeTemp);
1998 }
1999 else
2000 {
2001 /* Build the name */
2002 sprintf_nt(Buffer, "%wZ", &BaseName);
2003 }
2004
2005 /* Setup the ansi string */
2006 RtlInitString(&AnsiTemp, Buffer);
2007
2008 /* Notify the debugger */
2009 DbgLoadImageSymbols(&AnsiTemp,
2010 LdrEntry->DllBase,
2011 (ULONG_PTR)ZwCurrentProcess());
2012 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
2013 }
2014
2015 /* FIXME: Page the driver */
2016 ASSERT(Section == NULL);
2017
2018 /* Return pointers */
2019 *ModuleObject = LdrEntry;
2020 *ImageBaseAddress = LdrEntry->DllBase;
2021
2022 Quickie:
2023 /* If we have a file handle, close it */
2024 if (FileHandle) ZwClose(FileHandle);
2025
2026 /* Check if we have the lock acquired */
2027 if (LockOwned)
2028 {
2029 /* Release the lock */
2030 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
2031 KeLeaveCriticalRegion();
2032 LockOwned = FALSE;
2033 }
2034
2035 /* Check if we had a prefix */
2036 if (NamePrefix) ExFreePool(PrefixName.Buffer);
2037
2038 /* Free the name buffer and return status */
2039 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
2040 return Status;
2041 }
2042
2043 /*
2044 * @implemented
2045 */
2046 PVOID
2047 NTAPI
2048 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
2049 {
2050 PVOID ProcAddress = NULL;
2051 ANSI_STRING AnsiRoutineName;
2052 NTSTATUS Status;
2053 PLIST_ENTRY NextEntry;
2054 PLDR_DATA_TABLE_ENTRY LdrEntry;
2055 BOOLEAN Found = FALSE;
2056 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
2057 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
2058 ULONG Modules = 0;
2059
2060 /* Convert routine to ansi name */
2061 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
2062 SystemRoutineName,
2063 TRUE);
2064 if (!NT_SUCCESS(Status)) return NULL;
2065
2066 /* Lock the list */
2067 KeEnterCriticalRegion();
2068 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
2069
2070 /* Loop the loaded module list */
2071 NextEntry = PsLoadedModuleList.Flink;
2072 while (NextEntry != &PsLoadedModuleList)
2073 {
2074 /* Get the entry */
2075 LdrEntry = CONTAINING_RECORD(NextEntry,
2076 LDR_DATA_TABLE_ENTRY,
2077 InLoadOrderLinks);
2078
2079 /* Check if it's the kernel or HAL */
2080 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
2081 {
2082 /* Found it */
2083 Found = TRUE;
2084 Modules++;
2085 }
2086 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
2087 {
2088 /* Found it */
2089 Found = TRUE;
2090 Modules++;
2091 }
2092
2093 /* Check if we found a valid binary */
2094 if (Found)
2095 {
2096 /* Find the procedure name */
2097 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
2098 &AnsiRoutineName);
2099
2100 /* Break out if we found it or if we already tried both modules */
2101 if (ProcAddress) break;
2102 if (Modules == 2) break;
2103 }
2104
2105 /* Keep looping */
2106 NextEntry = NextEntry->Flink;
2107 }
2108
2109 /* Release the lock */
2110 ExReleaseResourceLite(&PsLoadedModuleResource);
2111 KeLeaveCriticalRegion();
2112
2113 /* Free the string and return */
2114 RtlFreeAnsiString(&AnsiRoutineName);
2115 return ProcAddress;
2116 }
2117