- Use real NT KPCR address (0xFFDFF000).
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / loader.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 #define _NTSYSTEM_
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25 #undef DbgPrint
26
27 /* Load Address of Next Module */
28 ULONG_PTR NextModuleBase = KERNEL_BASE_PHYS;
29
30 /* Currently Opened Module */
31 PLOADER_MODULE CurrentModule = NULL;
32
33 /* Unrelocated Kernel Base in Virtual Memory */
34 ULONG_PTR KernelBase;
35
36 /* Kernel Entrypoint in Virtual Memory */
37 ULONG_PTR KernelEntryPoint;
38
39 /* Page Directory and Tables for non-PAE Systems */
40 extern PAGE_DIRECTORY_X86 startup_pagedirectory;
41 extern PAGE_DIRECTORY_X86 lowmem_pagetable;
42 extern PAGE_DIRECTORY_X86 kernel_pagetable;
43 extern PAGE_DIRECTORY_X86 hyperspace_pagetable;
44 extern PAGE_DIRECTORY_X86 apic_pagetable;
45 extern PAGE_DIRECTORY_X86 kpcr_pagetable;
46 extern PAGE_DIRECTORY_X86 kuser_pagetable;
47
48 PVOID
49 NTAPI
50 LdrPEGetExportByName(PVOID BaseAddress,
51 PUCHAR SymbolName,
52 USHORT Hint);
53
54 /* FUNCTIONS *****************************************************************/
55
56 /*++
57 * FrLdrStartup
58 * INTERNAL
59 *
60 * Prepares the system for loading the Kernel.
61 *
62 * Params:
63 * Magic - Multiboot Magic
64 *
65 * Returns:
66 * None.
67 *
68 * Remarks:
69 * None.
70 *
71 *--*/
72 VOID
73 NTAPI
74 FrLdrStartup(ULONG Magic)
75 {
76 /* Disable Interrupts */
77 _disable();
78
79 /* Re-initalize EFLAGS */
80 Ke386EraseFlags();
81
82 /* Initialize the page directory */
83 FrLdrSetupPageDirectory();
84
85 /* Initialize Paging, Write-Protection and Load NTOSKRNL */
86 FrLdrSetupPae(Magic);
87 }
88
89 /*++
90 * FrLdrSetupPae
91 * INTERNAL
92 *
93 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
94 * the system is UP.
95 *
96 * Params:
97 * Magic - Multiboot Magic
98 *
99 * Returns:
100 * None.
101 *
102 * Remarks:
103 * None.
104 *
105 *--*/
106 VOID
107 FASTCALL
108 FrLdrSetupPae(ULONG Magic)
109 {
110 ULONG_PTR PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectory;
111 ASMCODE PagedJump;
112
113 /* Set the PDBR */
114 __writecr3(PageDirectoryBaseAddress);
115
116 /* Enable Paging and Write Protect*/
117 __writecr0(__readcr0() | X86_CR0_PG | X86_CR0_WP);
118
119 /* Jump to Kernel */
120 PagedJump = (ASMCODE)(PVOID)(KernelEntryPoint);
121 PagedJump(Magic, &LoaderBlock);
122 }
123
124 /*++
125 * FrLdrSetupPageDirectory
126 * INTERNAL
127 *
128 * Sets up the ReactOS Startup Page Directory.
129 *
130 * Params:
131 * None.
132 *
133 * Returns:
134 * None.
135 *
136 * Remarks:
137 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
138 * As such, please note that PageFrameNumber == PageEntryNumber.
139 *
140 *--*/
141 VOID
142 FASTCALL
143 FrLdrSetupPageDirectory(VOID)
144 {
145 PPAGE_DIRECTORY_X86 PageDir;
146 ULONG KernelPageTableIndex;
147 ULONG i;
148
149 /* Get the Kernel Table Index */
150 KernelPageTableIndex = KernelBase >> PDE_SHIFT;
151
152 /* Get the Startup Page Directory */
153 PageDir = (PPAGE_DIRECTORY_X86)&startup_pagedirectory;
154
155 /* Set up the Low Memory PDE */
156 PageDir->Pde[LowMemPageTableIndex].Valid = 1;
157 PageDir->Pde[LowMemPageTableIndex].Write = 1;
158 PageDir->Pde[LowMemPageTableIndex].PageFrameNumber = PaPtrToPfn(lowmem_pagetable);
159
160 /* Set up the Kernel PDEs */
161 PageDir->Pde[KernelPageTableIndex].Valid = 1;
162 PageDir->Pde[KernelPageTableIndex].Write = 1;
163 PageDir->Pde[KernelPageTableIndex].PageFrameNumber = PaPtrToPfn(kernel_pagetable);
164 PageDir->Pde[KernelPageTableIndex + 1].Valid = 1;
165 PageDir->Pde[KernelPageTableIndex + 1].Write = 1;
166 PageDir->Pde[KernelPageTableIndex + 1].PageFrameNumber = PaPtrToPfn(kernel_pagetable + 4096);
167
168 /* Set up the Startup PDE */
169 PageDir->Pde[StartupPageTableIndex].Valid = 1;
170 PageDir->Pde[StartupPageTableIndex].Write = 1;
171 PageDir->Pde[StartupPageTableIndex].PageFrameNumber = PaPtrToPfn(startup_pagedirectory);
172
173 /* Set up the Hyperspace PDE */
174 PageDir->Pde[HyperspacePageTableIndex].Valid = 1;
175 PageDir->Pde[HyperspacePageTableIndex].Write = 1;
176 PageDir->Pde[HyperspacePageTableIndex].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable);
177
178 /* Set up the HAL PDE */
179 PageDir->Pde[HalPageTableIndex].Valid = 1;
180 PageDir->Pde[HalPageTableIndex].Write = 1;
181 PageDir->Pde[HalPageTableIndex].PageFrameNumber = PaPtrToPfn(apic_pagetable);
182
183 /* Set up Low Memory PTEs */
184 PageDir = (PPAGE_DIRECTORY_X86)&lowmem_pagetable;
185 for (i=0; i<1024; i++)
186 {
187 PageDir->Pde[i].Valid = 1;
188 PageDir->Pde[i].Write = 1;
189 PageDir->Pde[i].Owner = 1;
190 PageDir->Pde[i].PageFrameNumber = PaToPfn(i * PAGE_SIZE);
191 }
192
193 /* Set up Kernel PTEs */
194 PageDir = (PPAGE_DIRECTORY_X86)&kernel_pagetable;
195 for (i=0; i<1536; i++)
196 {
197 PageDir->Pde[i].Valid = 1;
198 PageDir->Pde[i].Write = 1;
199 PageDir->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS + i * PAGE_SIZE);
200 }
201
202 /* Setup APIC Base */
203 PageDir = (PPAGE_DIRECTORY_X86)&apic_pagetable;
204 PageDir->Pde[0].Valid = 1;
205 PageDir->Pde[0].Write = 1;
206 PageDir->Pde[0].CacheDisable = 1;
207 PageDir->Pde[0].WriteThrough = 1;
208 PageDir->Pde[0].PageFrameNumber = PaToPfn(HAL_BASE);
209 PageDir->Pde[0x200].Valid = 1;
210 PageDir->Pde[0x200].Write = 1;
211 PageDir->Pde[0x200].CacheDisable = 1;
212 PageDir->Pde[0x200].WriteThrough = 1;
213 PageDir->Pde[0x200].PageFrameNumber = PaToPfn(HAL_BASE + KERNEL_BASE_PHYS);
214
215 /* Setup KUSER_SHARED_DATA Base */
216 PageDir->Pde[0x1F0].Valid = 1;
217 PageDir->Pde[0x1F0].Write = 1;
218 PageDir->Pde[0x1F0].PageFrameNumber = 2;
219
220 /* Setup KPCR Base*/
221 PageDir->Pde[0x1FF].Valid = 1;
222 PageDir->Pde[0x1FF].Write = 1;
223 PageDir->Pde[0x1FF].PageFrameNumber = 1;
224 }
225
226 PLOADER_MODULE
227 NTAPI
228 LdrGetModuleObject(PCHAR ModuleName)
229 {
230 ULONG i;
231
232 for (i = 0; i < LoaderBlock.ModsCount; i++)
233 {
234 if (strstr(_strupr((PCHAR)reactos_modules[i].String), _strupr(ModuleName)))
235 {
236 return &reactos_modules[i];
237 }
238 }
239
240 return NULL;
241 }
242
243 PVOID
244 NTAPI
245 LdrPEFixupForward(IN PCHAR ForwardName)
246 {
247 CHAR NameBuffer[128];
248 PCHAR p;
249 PLOADER_MODULE ModuleObject;
250
251 strcpy(NameBuffer, ForwardName);
252 p = strchr(NameBuffer, '.');
253 if (p == NULL) return NULL;
254 *p = 0;
255
256 ModuleObject = LdrGetModuleObject(NameBuffer);
257 if (!ModuleObject)
258 {
259 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
260 return NULL;
261 }
262
263 return LdrPEGetExportByName((PVOID)ModuleObject->ModStart, (PUCHAR)(p + 1), 0xffff);
264 }
265
266 PVOID
267 NTAPI
268 LdrPEGetExportByName(PVOID BaseAddress,
269 PUCHAR SymbolName,
270 USHORT Hint)
271 {
272 PIMAGE_EXPORT_DIRECTORY ExportDir;
273 PULONG * ExFunctions;
274 PULONG * ExNames;
275 USHORT * ExOrdinals;
276 PVOID ExName;
277 ULONG Ordinal;
278 PVOID Function;
279 LONG minn, maxn, mid, res;
280 ULONG ExportDirSize;
281
282 /* HAL and NTOS use a virtual address, switch it to physical mode */
283 if ((ULONG_PTR)BaseAddress & KSEG0_BASE)
284 {
285 BaseAddress = RVA(BaseAddress, -KSEG0_BASE);
286 }
287
288 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
289 RtlImageDirectoryEntryToData(BaseAddress,
290 TRUE,
291 IMAGE_DIRECTORY_ENTRY_EXPORT,
292 &ExportDirSize);
293 if (!ExportDir)
294 {
295 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
296 return NULL;
297 }
298
299 /* The symbol names may be missing entirely */
300 if (!ExportDir->AddressOfNames)
301 {
302 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
303 return NULL;
304 }
305
306 /*
307 * Get header pointers
308 */
309 ExNames = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfNames);
310 ExOrdinals = (USHORT *)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
311 ExFunctions = (PULONG *)RVA(BaseAddress, ExportDir->AddressOfFunctions);
312
313 /*
314 * Check the hint first
315 */
316 if (Hint < ExportDir->NumberOfNames)
317 {
318 ExName = RVA(BaseAddress, ExNames[Hint]);
319 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
320 {
321 Ordinal = ExOrdinals[Hint];
322 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
323 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
324 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
325 {
326 Function = LdrPEFixupForward((PCHAR)Function);
327 if (Function == NULL)
328 {
329 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function);
330 }
331 return Function;
332 }
333
334 if (Function != NULL) return Function;
335 }
336 }
337
338 /*
339 * Binary search
340 */
341 minn = 0;
342 maxn = ExportDir->NumberOfNames - 1;
343 while (minn <= maxn)
344 {
345 mid = (minn + maxn) / 2;
346
347 ExName = RVA(BaseAddress, ExNames[mid]);
348 res = strcmp(ExName, (PCHAR)SymbolName);
349 if (res == 0)
350 {
351 Ordinal = ExOrdinals[mid];
352 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
353 if ((ULONG_PTR)Function >= (ULONG_PTR)ExportDir &&
354 (ULONG_PTR)Function < (ULONG_PTR)ExportDir + ExportDirSize)
355 {
356 Function = LdrPEFixupForward((PCHAR)Function);
357 if (Function == NULL)
358 {
359 DbgPrint("1: failed to find %s\n", Function);
360 }
361 return Function;
362 }
363 if (Function != NULL)
364 {
365 return Function;
366 }
367 }
368 else if (res > 0)
369 {
370 maxn = mid - 1;
371 }
372 else
373 {
374 minn = mid + 1;
375 }
376 }
377
378 ExName = RVA(BaseAddress, ExNames[mid]);
379 DbgPrint("2: failed to find %s\n",SymbolName);
380 return (PVOID)NULL;
381 }
382
383 NTSTATUS
384 NTAPI
385 LdrPEProcessImportDirectoryEntry(PVOID DriverBase,
386 PLOADER_MODULE LoaderModule,
387 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
388 {
389 PVOID* ImportAddressList;
390 PULONG FunctionNameList;
391
392 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
393 {
394 return STATUS_UNSUCCESSFUL;
395 }
396
397 /* Get the import address list. */
398 ImportAddressList = (PVOID*)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
399
400 /* Get the list of functions to import. */
401 if (ImportModuleDirectory->OriginalFirstThunk != 0)
402 {
403 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->OriginalFirstThunk);
404 }
405 else
406 {
407 FunctionNameList = (PULONG)RVA(DriverBase, ImportModuleDirectory->FirstThunk);
408 }
409
410 /* Walk through function list and fixup addresses. */
411 while (*FunctionNameList != 0L)
412 {
413 if ((*FunctionNameList) & 0x80000000)
414 {
415 DbgPrint("Failed to import ordinal from %s\n", LoaderModule->String);
416 return STATUS_UNSUCCESSFUL;
417 }
418 else
419 {
420 IMAGE_IMPORT_BY_NAME *pe_name;
421 pe_name = RVA(DriverBase, *FunctionNameList);
422 *ImportAddressList = LdrPEGetExportByName((PVOID)LoaderModule->ModStart, pe_name->Name, pe_name->Hint);
423
424 /* Fixup the address to be virtual */
425 *ImportAddressList = RVA(*ImportAddressList, KSEG0_BASE);
426
427 //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
428 if ((*ImportAddressList) == NULL)
429 {
430 DbgPrint("Failed to import %s from %s\n", pe_name->Name, LoaderModule->String);
431 return STATUS_UNSUCCESSFUL;
432 }
433 }
434 ImportAddressList++;
435 FunctionNameList++;
436 }
437 return STATUS_SUCCESS;
438 }
439
440 extern BOOLEAN FrLdrLoadDriver(PCHAR szFileName, INT nPos);
441
442 NTSTATUS
443 NTAPI
444 LdrPEGetOrLoadModule(IN PCHAR ModuleName,
445 IN PCHAR ImportedName,
446 IN PLOADER_MODULE* ImportedModule)
447 {
448 NTSTATUS Status = STATUS_SUCCESS;
449
450 *ImportedModule = LdrGetModuleObject(ImportedName);
451 if (*ImportedModule == NULL)
452 {
453 if (!FrLdrLoadDriver(ImportedName, 0))
454 {
455 return STATUS_UNSUCCESSFUL;
456 }
457 else
458 {
459 return LdrPEGetOrLoadModule
460 (ModuleName, ImportedName, ImportedModule);
461 }
462 }
463
464 return Status;
465 }
466
467 NTSTATUS
468 NTAPI
469 LdrPEFixupImports(IN PVOID DllBase,
470 IN PCHAR DllName)
471 {
472 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
473 PCHAR ImportedName;
474 NTSTATUS Status;
475 PLOADER_MODULE ImportedModule;
476 ULONG Size;
477
478 /* Process each import module */
479 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
480 RtlImageDirectoryEntryToData(DllBase,
481 TRUE,
482 IMAGE_DIRECTORY_ENTRY_IMPORT,
483 &Size);
484 while (ImportModuleDirectory && ImportModuleDirectory->Name)
485 {
486 /* Check to make sure that import lib is kernel */
487 ImportedName = (PCHAR) DllBase + ImportModuleDirectory->Name;
488 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
489
490 Status = LdrPEGetOrLoadModule(DllName, ImportedName, &ImportedModule);
491 if (!NT_SUCCESS(Status)) return Status;
492
493 Status = LdrPEProcessImportDirectoryEntry(DllBase, ImportedModule, ImportModuleDirectory);
494 if (!NT_SUCCESS(Status)) return Status;
495
496 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
497 ImportModuleDirectory++;
498 }
499
500 return STATUS_SUCCESS;
501 }
502
503 ULONG
504 NTAPI
505 FrLdrReMapImage(IN PVOID Base,
506 IN PVOID LoadBase)
507 {
508 PIMAGE_NT_HEADERS NtHeader;
509 PIMAGE_SECTION_HEADER Section;
510 ULONG i, Size, DriverSize = 0;
511
512 /* Get the first section */
513 NtHeader = RtlImageNtHeader(Base);
514 Section = IMAGE_FIRST_SECTION(NtHeader);
515
516 /* Allocate memory for the driver */
517 DriverSize = NtHeader->OptionalHeader.SizeOfImage;
518 LoadBase = MmAllocateMemoryAtAddress(DriverSize, LoadBase);
519 ASSERT(LoadBase);
520
521 /* Copy headers over */
522 RtlMoveMemory(LoadBase, Base, NtHeader->OptionalHeader.SizeOfHeaders);
523
524 /* Copy image sections into virtual section */
525 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
526 {
527 /* Get the size of this section and check if it's valid */
528 Size = Section[i].VirtualAddress + Section[i].Misc.VirtualSize;
529 if (Size <= DriverSize)
530 {
531 if (Section[i].SizeOfRawData)
532 {
533 /* Copy the data from the disk to the image */
534 RtlCopyMemory((PVOID)((ULONG_PTR)LoadBase +
535 Section[i].VirtualAddress),
536 (PVOID)((ULONG_PTR)Base +
537 Section[i].PointerToRawData),
538 Section[i].Misc.VirtualSize >
539 Section[i].SizeOfRawData ?
540 Section[i].SizeOfRawData :
541 Section[i].Misc.VirtualSize);
542 }
543 else
544 {
545 /* Clear the BSS area */
546 RtlZeroMemory((PVOID)((ULONG_PTR)LoadBase +
547 Section[i].VirtualAddress),
548 Section[i].Misc.VirtualSize);
549 }
550 }
551 }
552
553 /* Return the size of the mapped driver */
554 return DriverSize;
555 }
556
557 PVOID
558 NTAPI
559 FrLdrMapImage(IN FILE *Image,
560 IN PCHAR Name,
561 IN ULONG ImageType)
562 {
563 PVOID ImageBase, LoadBase, ReadBuffer;
564 ULONG ImageId = LoaderBlock.ModsCount;
565 ULONG ImageSize;
566 NTSTATUS Status = STATUS_SUCCESS;
567
568 /* Try to see, maybe it's loaded already */
569 if (LdrGetModuleObject(Name) != NULL)
570 {
571 /* It's loaded, return NULL. It would be wise to return
572 correct LoadBase, but it seems to be ignored almost everywhere */
573 return NULL;
574 }
575
576 /* Set the virtual (image) and physical (load) addresses */
577 LoadBase = (PVOID)NextModuleBase;
578 ImageBase = RVA(LoadBase, KSEG0_BASE);
579
580 /* Save the Image Size */
581 ImageSize = FsGetFileSize(Image);
582
583 /* Set the file pointer to zero */
584 FsSetFilePointer(Image, 0);
585
586 /* Allocate a temporary buffer for the read */
587 ReadBuffer = MmAllocateMemory(ImageSize);
588
589 /* Load the file image */
590 FsReadFile(Image, ImageSize, NULL, ReadBuffer);
591
592 /* Map it into virtual memory */
593 ImageSize = FrLdrReMapImage(ReadBuffer, LoadBase);
594
595 /* Free the temporary buffer */
596 MmFreeMemory(ReadBuffer);
597
598 /* Calculate Difference between Real Base and Compiled Base*/
599 Status = LdrRelocateImageWithBias(LoadBase,
600 (ULONG_PTR)ImageBase -
601 (ULONG_PTR)LoadBase,
602 "FreeLdr",
603 STATUS_SUCCESS,
604 STATUS_UNSUCCESSFUL,
605 STATUS_UNSUCCESSFUL);
606 if (!NT_SUCCESS(Status))
607 {
608 /* Fail */
609 DbgPrint("Failed to relocate image: %s\n", Name);
610 return NULL;
611 }
612
613 /* Fill out Module Data Structure */
614 reactos_modules[ImageId].ModStart = (ULONG_PTR)ImageBase;
615 reactos_modules[ImageId].ModEnd = (ULONG_PTR)ImageBase + ImageSize;
616 strcpy(reactos_module_strings[ImageId], Name);
617 reactos_modules[ImageId].String = (ULONG_PTR)reactos_module_strings[ImageId];
618 LoaderBlock.ModsCount++;
619
620 /* Increase the next Load Base */
621 NextModuleBase = ROUND_UP(NextModuleBase + ImageSize, PAGE_SIZE);
622
623 /* Perform import fixups */
624 if (!NT_SUCCESS(LdrPEFixupImports(LoadBase, Name)))
625 {
626 /* Fixup failed, just don't include it in the list */
627 // NextModuleBase = OldNextModuleBase;
628 LoaderBlock.ModsCount = ImageId;
629 return NULL;
630 }
631
632 /* Return the final mapped address */
633 return LoadBase;
634 }
635
636 ULONG_PTR
637 NTAPI
638 FrLdrLoadModule(FILE *ModuleImage,
639 LPCSTR ModuleName,
640 PULONG ModuleSize)
641 {
642 ULONG LocalModuleSize;
643 PLOADER_MODULE ModuleData;
644 LPSTR NameBuffer;
645 LPSTR TempName;
646
647 /* Get current module data structure and module name string array */
648 ModuleData = &reactos_modules[LoaderBlock.ModsCount];
649
650 /* Get only the Module Name */
651 do {
652
653 TempName = strchr(ModuleName, '\\');
654
655 if(TempName) {
656 ModuleName = TempName + 1;
657 }
658
659 } while(TempName);
660 NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
661
662 /* Get Module Size */
663 LocalModuleSize = FsGetFileSize(ModuleImage);
664
665 /* Fill out Module Data Structure */
666 ModuleData->ModStart = NextModuleBase;
667 ModuleData->ModEnd = NextModuleBase + LocalModuleSize;
668
669 /* Save name */
670 strcpy(NameBuffer, ModuleName);
671 ModuleData->String = (ULONG_PTR)NameBuffer;
672
673 /* Load the file image */
674 FsReadFile(ModuleImage, LocalModuleSize, NULL, (PVOID)NextModuleBase);
675
676 /* Move to next memory block and increase Module Count */
677 NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
678 LoaderBlock.ModsCount++;
679 // DbgPrint("NextBase, ImageSize, ModStart, ModEnd %p %p %p %p\n",
680 // NextModuleBase, LocalModuleSize, ModuleData->ModStart, ModuleData->ModEnd);
681
682 /* Return Module Size if required */
683 if (ModuleSize != NULL) {
684 *ModuleSize = LocalModuleSize;
685 }
686
687 return(ModuleData->ModStart);
688 }
689
690 ULONG_PTR
691 NTAPI
692 FrLdrCreateModule(LPCSTR ModuleName)
693 {
694 PLOADER_MODULE ModuleData;
695 LPSTR NameBuffer;
696
697 /* Get current module data structure and module name string array */
698 ModuleData = &reactos_modules[LoaderBlock.ModsCount];
699 NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
700
701 /* Set up the structure */
702 ModuleData->ModStart = NextModuleBase;
703 ModuleData->ModEnd = -1;
704
705 /* Copy the name */
706 strcpy(NameBuffer, ModuleName);
707 ModuleData->String = (ULONG_PTR)NameBuffer;
708
709 /* Set the current Module */
710 CurrentModule = ModuleData;
711
712 /* Return Module Base Address */
713 return(ModuleData->ModStart);
714 }
715
716 BOOLEAN
717 NTAPI
718 FrLdrCloseModule(ULONG_PTR ModuleBase,
719 ULONG ModuleSize)
720 {
721 PLOADER_MODULE ModuleData = CurrentModule;
722
723 /* Make sure a module is opened */
724 if (ModuleData) {
725
726 /* Make sure this is the right module and that it hasn't been closed */
727 if ((ModuleBase == ModuleData->ModStart) && (ModuleData->ModEnd == (ULONG_PTR)-1)) {
728
729 /* Close the Module */
730 ModuleData->ModEnd = ModuleData->ModStart + ModuleSize;
731
732 /* Set the next Module Base and increase the number of modules */
733 NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
734 LoaderBlock.ModsCount++;
735
736 /* Close the currently opened module */
737 CurrentModule = NULL;
738
739 /* Success */
740 return(TRUE);
741 }
742 }
743
744 /* Failure path */
745 return(FALSE);
746 }