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