fix build
[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 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 LIST_ENTRY PsLoadedModuleList;
18 KSPIN_LOCK PsLoadedModuleSpinLock;
19 PVOID PsNtosImageBase;
20
21 /* FUNCTIONS *****************************************************************/
22
23 VOID
24 NTAPI
25 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
26 IN PVOID OldBase,
27 IN PVOID NewBase,
28 IN ULONG Size)
29 {
30 ULONG_PTR OldBaseTop, Delta;
31 PLDR_DATA_TABLE_ENTRY LdrEntry;
32 PLIST_ENTRY NextEntry;
33 ULONG ImportSize;
34 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
35 PULONG ImageThunk;
36
37 /* Calculate the top and delta */
38 OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
39 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
40
41 /* Loop the loader block */
42 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
43 NextEntry != &LoaderBlock->LoadOrderListHead;
44 NextEntry = NextEntry->Flink)
45 {
46 /* Get the loader entry */
47 LdrEntry = CONTAINING_RECORD(NextEntry,
48 LDR_DATA_TABLE_ENTRY,
49 InLoadOrderLinks);
50
51 /* Get the import table */
52 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
53 TRUE,
54 IMAGE_DIRECTORY_ENTRY_IMPORT,
55 &ImportSize);
56 if (!ImportDescriptor) continue;
57
58 /* Make sure we have an IAT */
59 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
60 while ((ImportDescriptor->Name) &&
61 (ImportDescriptor->OriginalFirstThunk))
62 {
63 /* Get the image thunk */
64 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
65 ImportDescriptor->FirstThunk);
66 while (*ImageThunk)
67 {
68 /* Check if it's within this module */
69 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
70 {
71 /* Relocate it */
72 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
73 ImageThunk, *ImageThunk, *ImageThunk + Delta);
74 *ImageThunk += Delta;
75 }
76
77 /* Go to the next thunk */
78 ImageThunk++;
79 }
80
81 /* Go to the next import */
82 ImportDescriptor++;
83 }
84 }
85 }
86
87 NTSTATUS
88 NTAPI
89 MiSnapThunk(IN PVOID DllBase,
90 IN PVOID ImageBase,
91 IN PIMAGE_THUNK_DATA Name,
92 IN PIMAGE_THUNK_DATA Address,
93 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
94 IN ULONG ExportSize,
95 IN BOOLEAN SnapForwarder,
96 OUT PCHAR *MissingApi)
97 {
98 BOOLEAN IsOrdinal;
99 USHORT Ordinal;
100 PULONG NameTable;
101 PUSHORT OrdinalTable;
102 PIMAGE_IMPORT_BY_NAME NameImport;
103 USHORT Hint;
104 ULONG Low = 0, Mid = 0, High;
105 LONG Ret;
106 NTSTATUS Status;
107 PCHAR MissingForwarder;
108 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
109 PULONG ExportTable;
110 ANSI_STRING DllName;
111 UNICODE_STRING ForwarderName;
112 PLIST_ENTRY NextEntry;
113 PLDR_DATA_TABLE_ENTRY LdrEntry;
114 ULONG ForwardExportSize;
115 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
116 PIMAGE_IMPORT_BY_NAME ForwardName;
117 ULONG ForwardLength;
118 IMAGE_THUNK_DATA ForwardThunk;
119 PAGED_CODE();
120
121 /* Check if this is an ordinal */
122 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
123 if ((IsOrdinal) && !(SnapForwarder))
124 {
125 /* Get the ordinal number and set it as missing */
126 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
127 ExportDirectory->Base);
128 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
129 }
130 else
131 {
132 /* Get the VA if we don't have to snap */
133 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
134 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
135
136 /* Copy the procedure name */
137 strncpy(*MissingApi,
138 (PCHAR)&NameImport->Name[0],
139 MAXIMUM_FILENAME_LENGTH - 1);
140
141 /* Setup name tables */
142 DPRINT("Import name: %s\n", NameImport->Name);
143 NameTable = (PULONG)((ULONG_PTR)DllBase +
144 ExportDirectory->AddressOfNames);
145 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
146 ExportDirectory->AddressOfNameOrdinals);
147
148 /* Get the hint and check if it's valid */
149 Hint = NameImport->Hint;
150 if ((Hint < ExportDirectory->NumberOfNames) &&
151 !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
152 {
153 /* We have a match, get the ordinal number from here */
154 Ordinal = OrdinalTable[Hint];
155 }
156 else
157 {
158 /* Do a binary search */
159 High = ExportDirectory->NumberOfNames - 1;
160 while (High >= Low)
161 {
162 /* Get new middle value */
163 Mid = (Low + High) >> 1;
164
165 /* Compare name */
166 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
167 if (Ret < 0)
168 {
169 /* Update high */
170 High = Mid - 1;
171 }
172 else if (Ret > 0)
173 {
174 /* Update low */
175 Low = Mid + 1;
176 }
177 else
178 {
179 /* We got it */
180 break;
181 }
182 }
183
184 /* Check if we couldn't find it */
185 if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
186
187 /* Otherwise, this is the ordinal */
188 Ordinal = OrdinalTable[Mid];
189 }
190 }
191
192 /* Check if the ordinal is invalid */
193 if (Ordinal >= ExportDirectory->NumberOfFunctions)
194 {
195 /* Fail */
196 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
197 }
198 else
199 {
200 /* In case the forwarder is missing */
201 MissingForwarder = NameBuffer;
202
203 /* Resolve the address and write it */
204 ExportTable = (PULONG)((ULONG_PTR)DllBase +
205 ExportDirectory->AddressOfFunctions);
206 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
207
208 /* Assume success from now on */
209 Status = STATUS_SUCCESS;
210
211 /* Check if the function is actually a forwarder */
212 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
213 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
214 {
215 /* Now assume failure in case the forwarder doesn't exist */
216 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
217
218 /* Build the forwarder name */
219 DllName.Buffer = (PCHAR)Address->u1.Function;
220 DllName.Length = strchr(DllName.Buffer, '.') -
221 DllName.Buffer +
222 sizeof(ANSI_NULL);
223 DllName.MaximumLength = DllName.Length;
224
225 /* Convert it */
226 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
227 &DllName,
228 TRUE)))
229 {
230 /* We failed, just return an error */
231 return Status;
232 }
233
234 /* Loop the module list */
235 NextEntry = PsLoadedModuleList.Flink;
236 while (NextEntry != &PsLoadedModuleList)
237 {
238 /* Get the loader entry */
239 LdrEntry = CONTAINING_RECORD(NextEntry,
240 LDR_DATA_TABLE_ENTRY,
241 InLoadOrderLinks);
242
243 /* Check if it matches */
244 if (RtlPrefixString((PSTRING)&ForwarderName,
245 (PSTRING)&LdrEntry->BaseDllName,
246 TRUE))
247 {
248 /* Get the forwarder export directory */
249 ForwardExportDirectory =
250 RtlImageDirectoryEntryToData(LdrEntry->DllBase,
251 TRUE,
252 IMAGE_DIRECTORY_ENTRY_EXPORT,
253 &ForwardExportSize);
254 if (!ForwardExportDirectory) break;
255
256 /* Allocate a name entry */
257 ForwardLength = strlen(DllName.Buffer + DllName.Length) +
258 sizeof(ANSI_NULL);
259 ForwardName = ExAllocatePoolWithTag(PagedPool,
260 sizeof(*ForwardName) +
261 ForwardLength,
262 TAG_LDR_WSTR);
263 if (!ForwardName) break;
264
265 /* Copy the data */
266 RtlCopyMemory(&ForwardName->Name[0],
267 DllName.Buffer + DllName.Length,
268 ForwardLength);
269 ForwardName->Hint = 0;
270
271 /* Set the new address */
272 *(PULONG)&ForwardThunk.u1.AddressOfData = (ULONG)ForwardName;
273
274 /* Snap the forwarder */
275 Status = MiSnapThunk(LdrEntry->DllBase,
276 ImageBase,
277 &ForwardThunk,
278 &ForwardThunk,
279 ForwardExportDirectory,
280 ForwardExportSize,
281 TRUE,
282 &MissingForwarder);
283
284 /* Free the forwarder name and set the thunk */
285 ExFreePool(ForwardName);
286 Address->u1 = ForwardThunk.u1;
287 break;
288 }
289
290 /* Go to the next entry */
291 NextEntry = NextEntry->Flink;
292 }
293
294 /* Free the name */
295 RtlFreeUnicodeString(&ForwarderName);
296 }
297 }
298
299 /* Return status */
300 return Status;
301 }
302
303 NTSTATUS
304 NTAPI
305 MiResolveImageReferences(IN PVOID ImageBase,
306 IN PUNICODE_STRING ImageFileDirectory,
307 IN PUNICODE_STRING NamePrefix OPTIONAL,
308 OUT PCHAR *MissingApi,
309 OUT PWCHAR *MissingDriver,
310 OUT PLOAD_IMPORTS *LoadImports)
311 {
312 PCHAR MissingApiBuffer = *MissingApi, ImportName;
313 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
314 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
315 PLOAD_IMPORTS LoadedImports;
316 ULONG GdiLink, NormalLink, i;
317 BOOLEAN ReferenceNeeded, Loaded;
318 ANSI_STRING TempString;
319 UNICODE_STRING NameString, DllName;
320 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
321 PVOID ImportBase, DllBase;
322 PLIST_ENTRY NextEntry;
323 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
324 NTSTATUS Status;
325 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
326 PAGED_CODE();
327 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
328 __FUNCTION__, ImageBase, ImageFileDirectory);
329
330 /* Assume no imports */
331 *LoadImports = (PVOID)-2;
332
333 /* Get the import descriptor */
334 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
335 TRUE,
336 IMAGE_DIRECTORY_ENTRY_IMPORT,
337 &ImportSize);
338 if (!ImportDescriptor) return STATUS_SUCCESS;
339
340 /* Loop all imports to count them */
341 for (CurrentImport = ImportDescriptor;
342 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
343 CurrentImport++)
344 {
345 /* One more */
346 ImportCount++;
347 }
348
349 /* Make sure we have non-zero imports */
350 if (ImportCount)
351 {
352 /* Calculate and allocate the list we'll need */
353 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
354 LoadedImports = ExAllocatePoolWithTag(PagedPool,
355 LoadedImportsSize,
356 TAG_LDR_WSTR);
357 if (LoadedImports)
358 {
359 /* Zero it and set the count */
360 RtlZeroMemory(LoadedImports, LoadedImportsSize);
361 LoadedImports->Count = ImportCount;
362 }
363 }
364 else
365 {
366 /* No table */
367 LoadedImports = NULL;
368 }
369
370 /* Reset the import count and loop descriptors again */
371 ImportCount = GdiLink = NormalLink = 0;
372 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
373 {
374 /* Get the name */
375 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
376
377 /* Check if this is a GDI driver */
378 GdiLink = GdiLink |
379 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
380
381 /* We can also allow dxapi */
382 NormalLink = NormalLink |
383 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
384 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
385
386 /* Check if this is a valid GDI driver */
387 if ((GdiLink) && (NormalLink))
388 {
389 /* It's not, it's importing stuff it shouldn't be! */
390 DPRINT1("Invalid driver!\n");
391 //MiDereferenceImports(LoadedImports);
392 if (LoadedImports) ExFreePool(LoadedImports);
393 return STATUS_PROCEDURE_NOT_FOUND;
394 }
395
396 /* Check if this is a "core" import, which doesn't get referenced */
397 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
398 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
399 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
400 {
401 /* Don't reference this */
402 ReferenceNeeded = FALSE;
403 }
404 else
405 {
406 /* Reference these modules */
407 ReferenceNeeded = TRUE;
408 }
409
410 /* Now setup a unicode string for the import */
411 RtlInitAnsiString(&TempString, ImportName);
412 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
413 if (!NT_SUCCESS(Status))
414 {
415 /* Failed */
416 //MiDereferenceImports(LoadedImports);
417 if (LoadedImports) ExFreePool(LoadedImports);
418 return Status;
419 }
420
421 /* We don't support name prefixes yet */
422 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
423
424 /* Remember that we haven't loaded the import at this point */
425 CheckDllState:
426 Loaded = FALSE;
427 ImportBase = NULL;
428
429 /* Loop the driver list */
430 NextEntry = PsLoadedModuleList.Flink;
431 while (NextEntry != &PsLoadedModuleList)
432 {
433 /* Get the loader entry and compare the name */
434 LdrEntry = CONTAINING_RECORD(NextEntry,
435 LDR_DATA_TABLE_ENTRY,
436 InLoadOrderLinks);
437 if (RtlEqualUnicodeString(&NameString,
438 &LdrEntry->BaseDllName,
439 TRUE))
440 {
441 /* Get the base address */
442 ImportBase = LdrEntry->DllBase;
443
444 /* Check if we haven't loaded yet, and we need references */
445 if (!(Loaded) && (ReferenceNeeded))
446 {
447 /* Make sure we're not already loading */
448 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
449 {
450 /* Increase the load count */
451 LdrEntry->LoadCount++;
452 }
453 }
454
455 /* Done, break out */
456 break;
457 }
458
459 /* Go to the next entry */
460 NextEntry = NextEntry->Flink;
461 }
462
463 /* Check if we haven't loaded the import yet */
464 if (!ImportBase)
465 {
466 /* Setup the import DLL name */
467 DllName.MaximumLength = NameString.Length +
468 ImageFileDirectory->Length +
469 sizeof(UNICODE_NULL);
470 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
471 DllName.MaximumLength,
472 TAG_LDR_WSTR);
473 if (DllName.Buffer)
474 {
475 /* Setup the base length and copy it */
476 DllName.Length = ImageFileDirectory->Length;
477 RtlCopyMemory(DllName.Buffer,
478 ImageFileDirectory->Buffer,
479 ImageFileDirectory->Length);
480
481 /* Now add the import name and null-terminate it */
482 RtlAppendStringToString((PSTRING)&DllName,
483 (PSTRING)&NameString);
484 DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;
485
486 /* Load the image */
487 Status = MmLoadSystemImage(&DllName,
488 NamePrefix,
489 NULL,
490 0,
491 (PVOID)&DllEntry,
492 &DllBase);
493 if (NT_SUCCESS(Status))
494 {
495 /* We can free the DLL Name */
496 ExFreePool(DllName.Buffer);
497 }
498 else
499 {
500 /* Fill out the information for the error */
501 DPRINT1("Failed to import: %S\n", DllName.Buffer);
502 *MissingDriver = DllName.Buffer;
503 *(PULONG)MissingDriver |= 1;
504 *MissingApi = NULL;
505 }
506 }
507 else
508 {
509 /* We're out of resources */
510 Status = STATUS_INSUFFICIENT_RESOURCES;
511 }
512
513 /* Check if we're OK until now */
514 if (NT_SUCCESS(Status))
515 {
516 /* We're now loaded */
517 Loaded = TRUE;
518
519 /* Sanity check */
520 ASSERT(DllBase = DllEntry->DllBase);
521
522 /* Call the initialization routines */
523 #if 0
524 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
525 if (!NT_SUCCESS(Status))
526 {
527 /* We failed, unload the image */
528 MmUnloadSystemImage(DllEntry);
529 while (TRUE);
530 Loaded = FALSE;
531 }
532 #endif
533 }
534
535 /* Check if we failed by here */
536 if (!NT_SUCCESS(Status))
537 {
538 /* Cleanup and return */
539 DPRINT1("Failed loading import\n");
540 RtlFreeUnicodeString(&NameString);
541 //MiDereferenceImports(LoadedImports);
542 if (LoadedImports) ExFreePool(LoadedImports);
543 return Status;
544 }
545
546 /* Loop again to make sure that everything is OK */
547 goto CheckDllState;
548 }
549
550 /* Check if we're support to reference this import */
551 if ((ReferenceNeeded) && (LoadedImports))
552 {
553 /* Make sure we're not already loading */
554 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
555 {
556 /* Add the entry */
557 LoadedImports->Entry[ImportCount] = LdrEntry;
558 ImportCount++;
559 }
560 }
561
562 /* Free the import name */
563 RtlFreeUnicodeString(&NameString);
564
565 /* Set the missing driver name and get the export directory */
566 *MissingDriver = LdrEntry->BaseDllName.Buffer;
567 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
568 TRUE,
569 IMAGE_DIRECTORY_ENTRY_EXPORT,
570 &ExportSize);
571 if (!ExportDirectory)
572 {
573 /* Cleanup and return */
574 DPRINT1("Invalid driver: %wZ\n", &LdrEntry->BaseDllName);
575 //MiDereferenceImports(LoadedImports);
576 if (LoadedImports) ExFreePool(LoadedImports);
577 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
578 }
579
580 /* Make sure we have an IAT */
581 if (ImportDescriptor->OriginalFirstThunk)
582 {
583 /* Get the first thunks */
584 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
585 ImportDescriptor->OriginalFirstThunk);
586 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
587 ImportDescriptor->FirstThunk);
588
589 /* Loop the IAT */
590 while (OrigThunk->u1.AddressOfData)
591 {
592 /* Snap thunk */
593 Status = MiSnapThunk(ImportBase,
594 ImageBase,
595 OrigThunk++,
596 FirstThunk++,
597 ExportDirectory,
598 ExportSize,
599 FALSE,
600 MissingApi);
601 if (!NT_SUCCESS(Status))
602 {
603 /* Cleanup and return */
604 //MiDereferenceImports(LoadedImports);
605 if (LoadedImports) ExFreePool(LoadedImports);
606 return Status;
607 }
608
609 /* Reset the buffer */
610 *MissingApi = MissingApiBuffer;
611 }
612 }
613
614 /* Go to the next import */
615 ImportDescriptor++;
616 }
617
618 /* Check if we have an import list */
619 if (LoadedImports)
620 {
621 /* Reset the count again, and loop entries*/
622 ImportCount = 0;
623 for (i = 0; i < LoadedImports->Count; i++)
624 {
625 if (LoadedImports->Entry[i])
626 {
627 /* Got an entry, OR it with 1 in case it's the single entry */
628 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
629 ImportCount++;
630 }
631 }
632
633 /* Check if we had no imports */
634 if (!ImportCount)
635 {
636 /* Free the list and set it to no imports */
637 ExFreePool(LoadedImports);
638 LoadedImports = (PVOID)-2;
639 }
640 else if (ImportCount == 1)
641 {
642 /* Just one entry, we can free the table and only use our entry */
643 ExFreePool(LoadedImports);
644 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
645 }
646 else if (ImportCount != LoadedImports->Count)
647 {
648 /* FIXME: Can this happen? */
649 DPRINT1("Unhandled scenario\n");
650 while (TRUE);
651 }
652
653 /* Return the list */
654 *LoadImports = LoadedImports;
655 }
656
657 /* Return success */
658 return STATUS_SUCCESS;
659 }
660
661 VOID
662 NTAPI
663 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
664 {
665 PLIST_ENTRY NextEntry;
666 ULONG i = 0;
667 PIMAGE_NT_HEADERS NtHeader;
668 PLDR_DATA_TABLE_ENTRY LdrEntry;
669 PIMAGE_FILE_HEADER FileHeader;
670 BOOLEAN ValidRelocs;
671 PIMAGE_DATA_DIRECTORY DataDirectory;
672 PVOID DllBase, NewImageAddress;
673 NTSTATUS Status;
674 ULONG DriverSize = 0, Size;
675 PIMAGE_SECTION_HEADER Section;
676
677 /* Loop driver list */
678 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
679 NextEntry != &LoaderBlock->LoadOrderListHead;
680 NextEntry = NextEntry->Flink)
681 {
682 /* Get the loader entry and NT header */
683 LdrEntry = CONTAINING_RECORD(NextEntry,
684 LDR_DATA_TABLE_ENTRY,
685 InLoadOrderLinks);
686 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
687
688 /* Debug info */
689 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
690 LdrEntry->DllBase,
691 (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,
692 &LdrEntry->FullDllName);
693
694 /* Skip kernel and HAL */
695 /* ROS HACK: Skip BOOTVID/KDCOM too */
696 i++;
697 if (i <= 4) continue;
698
699 /* Skip non-drivers */
700 if (!NtHeader) continue;
701
702 #if 1 // Disable for FreeLDR 2.5
703 /* Get header pointers */
704 Section = IMAGE_FIRST_SECTION(NtHeader);
705
706 /* Determine the size of the module */
707 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
708 {
709 /* Skip this section if we're not supposed to load it */
710 if (!(Section[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
711 {
712 /* Add the size of this section into the total size */
713 Size = Section[i].VirtualAddress + Section[i].Misc.VirtualSize;
714 DriverSize = max(DriverSize, Size);
715 }
716 }
717
718 /* Round up the driver size to section alignment */
719 DriverSize = ROUND_UP(DriverSize, NtHeader->OptionalHeader.SectionAlignment);
720 #endif
721
722 /* Get the file header and make sure we can relocate */
723 FileHeader = &NtHeader->FileHeader;
724 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
725 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
726 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
727
728 /* Everything made sense until now, check the relocation section too */
729 DataDirectory = &NtHeader->OptionalHeader.
730 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
731 if (!DataDirectory->VirtualAddress)
732 {
733 /* We don't really have relocations */
734 ValidRelocs = FALSE;
735 }
736 else
737 {
738 /* Make sure the size is valid */
739 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
740 LdrEntry->SizeOfImage)
741 {
742 /* They're not, skip */
743 continue;
744 }
745
746 /* We have relocations */
747 ValidRelocs = TRUE;
748 }
749
750 /* Remember the original address */
751 DllBase = LdrEntry->DllBase;
752
753 /* Allocate a virtual section for the module */
754 NewImageAddress = MmAllocateSection(DriverSize, NULL);
755 if (!NewImageAddress)
756 {
757 /* Shouldn't happen */
758 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
759 while (TRUE);
760 }
761
762 /* Sanity check */
763 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
764 ASSERT(ExpInitializationPhase == 0);
765
766 #if 0 // Enable for FreeLDR 2.5
767 /* Now copy the entire driver over */
768 RtlCopyMemory(NewImageAddress, DllBase, DriverSize);
769 #else
770 /* Copy headers over */
771 RtlCopyMemory(NewImageAddress,
772 DllBase,
773 NtHeader->OptionalHeader.SizeOfHeaders);
774
775 /* Copy image sections into virtual section */
776 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
777 {
778 /* Get the size of this section and check if it's valid and on-disk */
779 Size = Section[i].VirtualAddress + Section[i].Misc.VirtualSize;
780 if ((Size <= DriverSize) && (Section[i].SizeOfRawData))
781 {
782 /* Copy the data from the disk to the image */
783 RtlCopyMemory((PVOID)((ULONG_PTR)NewImageAddress +
784 Section[i].VirtualAddress),
785 (PVOID)((ULONG_PTR)DllBase +
786 Section[i].PointerToRawData),
787 Section[i].Misc.VirtualSize >
788 Section[i].SizeOfRawData ?
789 Section[i].SizeOfRawData :
790 Section[i].Misc.VirtualSize);
791 }
792 }
793 #endif
794
795 /* Sanity check */
796 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
797
798 /* Set the image base to the old address */
799 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
800
801 /* Check if we had relocations */
802 if (ValidRelocs)
803 {
804 /* Relocate the image */
805 Status = LdrRelocateImageWithBias(NewImageAddress,
806 0,
807 "SYSLDR",
808 STATUS_SUCCESS,
809 STATUS_CONFLICTING_ADDRESSES,
810 STATUS_INVALID_IMAGE_FORMAT);
811 if (!NT_SUCCESS(Status))
812 {
813 /* This shouldn't happen */
814 DPRINT1("Relocations failed!\n");
815 while (TRUE);
816 }
817 }
818
819 /* Update the loader entry */
820 LdrEntry->DllBase = NewImageAddress;
821
822 /* Update the thunks */
823 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
824 MiUpdateThunks(LoaderBlock,
825 DllBase,
826 NewImageAddress,
827 LdrEntry->SizeOfImage);
828
829 /* Update the loader entry */
830 LdrEntry->Flags |= 0x01000000;
831 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
832 NtHeader->OptionalHeader.AddressOfEntryPoint);
833 LdrEntry->SizeOfImage = DriverSize;
834 }
835 }
836
837 BOOLEAN
838 NTAPI
839 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
840 {
841 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
842 PLIST_ENTRY ListHead, NextEntry;
843 ULONG EntrySize;
844
845 /* Setup the loaded module list and lock */
846 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
847 InitializeListHead(&PsLoadedModuleList);
848
849 /* Get loop variables and the kernel entry */
850 ListHead = &LoaderBlock->LoadOrderListHead;
851 NextEntry = ListHead->Flink;
852 LdrEntry = CONTAINING_RECORD(NextEntry,
853 LDR_DATA_TABLE_ENTRY,
854 InLoadOrderLinks);
855 PsNtosImageBase = LdrEntry->DllBase;
856
857 /* Loop the loader block */
858 while (NextEntry != ListHead)
859 {
860 /* Get the loader entry */
861 LdrEntry = CONTAINING_RECORD(NextEntry,
862 LDR_DATA_TABLE_ENTRY,
863 InLoadOrderLinks);
864
865 /* FIXME: ROS HACK. Make sure this is a driver */
866 if (!RtlImageNtHeader(LdrEntry->DllBase))
867 {
868 /* Skip this entry */
869 NextEntry= NextEntry->Flink;
870 continue;
871 }
872
873 /* Calculate the size we'll need and allocate a copy */
874 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
875 LdrEntry->BaseDllName.MaximumLength +
876 sizeof(UNICODE_NULL);
877 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
878 if (!NewEntry) return FALSE;
879
880 /* Copy the entry over */
881 *NewEntry = *LdrEntry;
882
883 /* Allocate the name */
884 NewEntry->FullDllName.Buffer =
885 ExAllocatePoolWithTag(PagedPool,
886 LdrEntry->FullDllName.MaximumLength +
887 sizeof(UNICODE_NULL),
888 TAG_LDR_WSTR);
889 if (!NewEntry->FullDllName.Buffer) return FALSE;
890
891 /* Set the base name */
892 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
893
894 /* Copy the full and base name */
895 RtlCopyMemory(NewEntry->FullDllName.Buffer,
896 LdrEntry->FullDllName.Buffer,
897 LdrEntry->FullDllName.MaximumLength);
898 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
899 LdrEntry->BaseDllName.Buffer,
900 LdrEntry->BaseDllName.MaximumLength);
901
902 /* Null-terminate the base name */
903 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
904 sizeof(WCHAR)] = UNICODE_NULL;
905
906 /* Insert the entry into the list */
907 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
908 NextEntry = NextEntry->Flink;
909 }
910
911 /* Build the import lists for the boot drivers */
912 //MiBuildImportsForBootDrivers();
913
914 /* We're done */
915 return TRUE;
916 }