3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
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.
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.
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.
27 /* Load Address of Next Module */
28 ULONG_PTR NextModuleBase
= KERNEL_BASE_PHYS
;
30 /* Currently Opened Module */
31 PLOADER_MODULE CurrentModule
= NULL
;
33 /* Unrelocated Kernel Base in Virtual Memory */
36 /* Kernel Entrypoint in Physical Memory */
37 ULONG_PTR KernelEntry
;
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
;
50 LdrPEGetExportByName(PVOID BaseAddress
,
54 /* FUNCTIONS *****************************************************************/
60 * Prepares the system for loading the Kernel.
63 * Magic - Multiboot Magic
74 FrLdrStartup(ULONG Magic
)
76 /* Disable Interrupts */
79 /* Re-initalize EFLAGS */
82 /* Initialize the page directory */
83 FrLdrSetupPageDirectory();
85 /* Initialize Paging, Write-Protection and Load NTOSKRNL */
93 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
97 * Magic - Multiboot Magic
108 FrLdrSetupPae(ULONG Magic
)
110 ULONG_PTR PageDirectoryBaseAddress
= (ULONG_PTR
)&startup_pagedirectory
;
114 __writecr3(PageDirectoryBaseAddress
);
116 /* Enable Paging and Write Protect*/
117 __writecr0(__readcr0() | X86_CR0_PG
| X86_CR0_WP
);
120 PagedJump
= (ASMCODE
)(PVOID
)(KernelEntryPoint
);
121 PagedJump(Magic
, &LoaderBlock
);
125 * FrLdrSetupPageDirectory
128 * Sets up the ReactOS Startup Page Directory.
137 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
138 * As such, please note that PageFrameNumber == PageEntryNumber.
143 FrLdrSetupPageDirectory(VOID
)
145 PPAGE_DIRECTORY_X86 PageDir
;
146 ULONG KernelPageTableIndex
;
149 /* Get the Kernel Table Index */
150 KernelPageTableIndex
= KernelBase
>> PDE_SHIFT
;
152 /* Get the Startup Page Directory */
153 PageDir
= (PPAGE_DIRECTORY_X86
)&startup_pagedirectory
;
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
);
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);
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
);
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
);
178 /* Set up the Apic PDE */
179 PageDir
->Pde
[ApicPageTableIndex
].Valid
= 1;
180 PageDir
->Pde
[ApicPageTableIndex
].Write
= 1;
181 PageDir
->Pde
[ApicPageTableIndex
].PageFrameNumber
= PaPtrToPfn(apic_pagetable
);
183 /* Set up the KPCR PDE */
184 PageDir
->Pde
[KpcrPageTableIndex
].Valid
= 1;
185 PageDir
->Pde
[KpcrPageTableIndex
].Write
= 1;
186 PageDir
->Pde
[KpcrPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kpcr_pagetable
);
188 /* Set up the KUSER PDE */
189 PageDir
->Pde
[KuserPageTableIndex
].Valid
= 1;
190 PageDir
->Pde
[KuserPageTableIndex
].Write
= 1;
191 PageDir
->Pde
[KuserPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kuser_pagetable
);
193 /* Set up Low Memory PTEs */
194 PageDir
= (PPAGE_DIRECTORY_X86
)&lowmem_pagetable
;
195 for (i
=0; i
<1024; i
++)
197 PageDir
->Pde
[i
].Valid
= 1;
198 PageDir
->Pde
[i
].Write
= 1;
199 PageDir
->Pde
[i
].Owner
= 1;
200 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(i
* PAGE_SIZE
);
203 /* Set up Kernel PTEs */
204 PageDir
= (PPAGE_DIRECTORY_X86
)&kernel_pagetable
;
205 for (i
=0; i
<1536; i
++)
207 PageDir
->Pde
[i
].Valid
= 1;
208 PageDir
->Pde
[i
].Write
= 1;
209 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
+ i
* PAGE_SIZE
);
212 /* Set up APIC PTEs */
213 PageDir
= (PPAGE_DIRECTORY_X86
)&apic_pagetable
;
214 PageDir
->Pde
[0].Valid
= 1;
215 PageDir
->Pde
[0].Write
= 1;
216 PageDir
->Pde
[0].CacheDisable
= 1;
217 PageDir
->Pde
[0].WriteThrough
= 1;
218 PageDir
->Pde
[0].PageFrameNumber
= PaToPfn(APIC_BASE
);
219 PageDir
->Pde
[0x200].Valid
= 1;
220 PageDir
->Pde
[0x200].Write
= 1;
221 PageDir
->Pde
[0x200].CacheDisable
= 1;
222 PageDir
->Pde
[0x200].WriteThrough
= 1;
223 PageDir
->Pde
[0x200].PageFrameNumber
= PaToPfn(APIC_BASE
+ KERNEL_BASE_PHYS
);
225 /* Set up KPCR PTEs */
226 PageDir
= (PPAGE_DIRECTORY_X86
)&kpcr_pagetable
;
227 PageDir
->Pde
[0].Valid
= 1;
228 PageDir
->Pde
[0].Write
= 1;
229 PageDir
->Pde
[0].PageFrameNumber
= 1;
231 /* Setup KUSER PTEs */
232 PageDir
= (PPAGE_DIRECTORY_X86
)&kuser_pagetable
;
233 for (i
= 0; i
< 1024; i
++)
235 /* SEetup each entry */
236 PageDir
->Pde
[i
].Valid
= 1;
237 PageDir
->Pde
[i
].Write
= 1;
238 PageDir
->Pde
[i
].Owner
= 1;
239 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(KI_USER_SHARED_DATA
+ i
* PAGE_SIZE
);
245 LdrGetModuleObject(PCHAR ModuleName
)
249 for (i
= 0; i
< LoaderBlock
.ModsCount
; i
++)
251 if (strstr(_strupr((PCHAR
)reactos_modules
[i
].String
), _strupr(ModuleName
)))
253 return &reactos_modules
[i
];
262 LdrPEFixupForward(IN PCHAR ForwardName
)
264 CHAR NameBuffer
[128];
266 PLOADER_MODULE ModuleObject
;
268 strcpy(NameBuffer
, ForwardName
);
269 p
= strchr(NameBuffer
, '.');
270 if (p
== NULL
) return NULL
;
273 ModuleObject
= LdrGetModuleObject(NameBuffer
);
276 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer
);
280 return LdrPEGetExportByName((PVOID
)ModuleObject
->ModStart
, (PUCHAR
)(p
+ 1), 0xffff);
285 LdrPEGetExportByName(PVOID BaseAddress
,
289 PIMAGE_EXPORT_DIRECTORY ExportDir
;
290 PULONG
* ExFunctions
;
296 LONG minn
, maxn
, mid
, res
;
299 /* HAL and NTOS use a virtual address, switch it to physical mode */
300 if ((ULONG_PTR
)BaseAddress
& 0x80000000)
302 BaseAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
- KSEG0_BASE
+ 0x200000);
305 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
306 RtlImageDirectoryEntryToData(BaseAddress
,
308 IMAGE_DIRECTORY_ENTRY_EXPORT
,
312 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
316 /* The symbol names may be missing entirely */
317 if (!ExportDir
->AddressOfNames
)
319 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
324 * Get header pointers
326 ExNames
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfNames
);
327 ExOrdinals
= (USHORT
*)RVA(BaseAddress
, ExportDir
->AddressOfNameOrdinals
);
328 ExFunctions
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfFunctions
);
331 * Check the hint first
333 if (Hint
< ExportDir
->NumberOfNames
)
335 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
336 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
338 Ordinal
= ExOrdinals
[Hint
];
339 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
340 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
341 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
343 Function
= LdrPEFixupForward((PCHAR
)Function
);
344 if (Function
== NULL
)
346 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function
);
351 if (Function
!= NULL
) return Function
;
359 maxn
= ExportDir
->NumberOfNames
- 1;
362 mid
= (minn
+ maxn
) / 2;
364 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
365 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
368 Ordinal
= ExOrdinals
[mid
];
369 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
370 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
371 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
373 Function
= LdrPEFixupForward((PCHAR
)Function
);
374 if (Function
== NULL
)
376 DbgPrint("1: failed to find %s\n", Function
);
380 if (Function
!= NULL
)
395 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
396 DbgPrint("2: failed to find %s\n",SymbolName
);
402 LdrPEProcessImportDirectoryEntry(PVOID DriverBase
,
403 PLOADER_MODULE LoaderModule
,
404 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
)
406 PVOID
* ImportAddressList
;
407 PULONG FunctionNameList
;
409 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->Name
== 0)
411 return STATUS_UNSUCCESSFUL
;
414 /* Get the import address list. */
415 ImportAddressList
= (PVOID
*)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
417 /* Get the list of functions to import. */
418 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
420 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->OriginalFirstThunk
);
424 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
427 /* Walk through function list and fixup addresses. */
428 while (*FunctionNameList
!= 0L)
430 if ((*FunctionNameList
) & 0x80000000)
432 DbgPrint("Failed to import ordinal from %s\n", LoaderModule
->String
);
433 return STATUS_UNSUCCESSFUL
;
437 IMAGE_IMPORT_BY_NAME
*pe_name
;
438 pe_name
= RVA(DriverBase
, *FunctionNameList
);
439 *ImportAddressList
= LdrPEGetExportByName((PVOID
)LoaderModule
->ModStart
, pe_name
->Name
, pe_name
->Hint
);
441 /* Fixup the address to be virtual */
442 *ImportAddressList
= (PVOID
)((ULONG_PTR
)*ImportAddressList
+ (KSEG0_BASE
- 0x200000));
444 //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
445 if ((*ImportAddressList
) == NULL
)
447 DbgPrint("Failed to import %s from %s\n", pe_name
->Name
, LoaderModule
->String
);
448 return STATUS_UNSUCCESSFUL
;
454 return STATUS_SUCCESS
;
459 LdrPEGetOrLoadModule(IN PCHAR ModuleName
,
460 IN PCHAR ImportedName
,
461 IN PLOADER_MODULE
* ImportedModule
)
463 NTSTATUS Status
= STATUS_SUCCESS
;
465 *ImportedModule
= LdrGetModuleObject(ImportedName
);
466 if (*ImportedModule
== NULL
)
469 * For now, we only support import-loading the HAL.
470 * Later, FrLdrLoadDriver should be made to share the same
471 * code, and we'll just call it instead.
473 if (!_stricmp(ImportedName
, "hal.dll") ||
474 !_stricmp(ImportedName
, "kdcom.dll") ||
475 !_stricmp(ImportedName
, "bootvid.dll"))
478 FrLdrLoadImage(ImportedName
, 10, FALSE
);
480 /* Return the new module */
481 *ImportedModule
= LdrGetModuleObject(ImportedName
);
482 if (*ImportedModule
== NULL
)
484 DbgPrint("Error loading import: %s\n", ImportedName
);
485 return STATUS_UNSUCCESSFUL
;
490 DbgPrint("Don't yet support loading new modules from imports\n");
491 Status
= STATUS_NOT_IMPLEMENTED
;
500 LdrPEFixupImports(IN PVOID DllBase
,
503 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
506 PLOADER_MODULE ImportedModule
;
509 /* Process each import module */
510 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
511 RtlImageDirectoryEntryToData(DllBase
,
513 IMAGE_DIRECTORY_ENTRY_IMPORT
,
515 while (ImportModuleDirectory
->Name
)
517 /* Check to make sure that import lib is kernel */
518 ImportedName
= (PCHAR
) DllBase
+ ImportModuleDirectory
->Name
;
519 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
521 Status
= LdrPEGetOrLoadModule(DllName
, ImportedName
, &ImportedModule
);
522 if (!NT_SUCCESS(Status
)) return Status
;
524 Status
= LdrPEProcessImportDirectoryEntry(DllBase
, ImportedModule
, ImportModuleDirectory
);
525 if (!NT_SUCCESS(Status
)) return Status
;
527 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
528 ImportModuleDirectory
++;
531 return STATUS_SUCCESS
;
536 FrLdrReMapImage(IN PVOID Base
,
539 PIMAGE_NT_HEADERS NtHeader
;
540 PIMAGE_SECTION_HEADER Section
;
541 ULONG i
, Size
, DriverSize
= 0;
543 /* Get the first section */
544 NtHeader
= RtlImageNtHeader(Base
);
545 Section
= IMAGE_FIRST_SECTION(NtHeader
);
547 /* Allocate memory for the driver */
548 DriverSize
= NtHeader
->OptionalHeader
.SizeOfImage
;
549 LoadBase
= MmAllocateMemoryAtAddress(DriverSize
, LoadBase
);
552 /* Copy headers over */
553 RtlMoveMemory(LoadBase
, Base
, NtHeader
->OptionalHeader
.SizeOfHeaders
);
555 /* Copy image sections into virtual section */
556 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
558 /* Get the size of this section and check if it's valid */
559 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
560 if (Size
<= DriverSize
)
562 if (Section
[i
].SizeOfRawData
)
564 /* Copy the data from the disk to the image */
565 RtlCopyMemory((PVOID
)((ULONG_PTR
)LoadBase
+
566 Section
[i
].VirtualAddress
),
567 (PVOID
)((ULONG_PTR
)Base
+
568 Section
[i
].PointerToRawData
),
569 Section
[i
].Misc
.VirtualSize
>
570 Section
[i
].SizeOfRawData
?
571 Section
[i
].SizeOfRawData
:
572 Section
[i
].Misc
.VirtualSize
);
576 /* Clear the BSS area */
577 RtlZeroMemory((PVOID
)((ULONG_PTR
)LoadBase
+
578 Section
[i
].VirtualAddress
),
579 Section
[i
].Misc
.VirtualSize
);
584 /* Return the size of the mapped driver */
590 FrLdrMapImage(IN
FILE *Image
,
594 PVOID ImageBase
, LoadBase
, ReadBuffer
;
595 ULONG ImageId
= LoaderBlock
.ModsCount
;
597 NTSTATUS Status
= STATUS_SUCCESS
;
599 /* Set the virtual (image) and physical (load) addresses */
600 LoadBase
= (PVOID
)NextModuleBase
;
601 ImageBase
= RVA(LoadBase
, -KERNEL_BASE_PHYS
+ KSEG0_BASE
);
603 /* Save the Image Size */
604 ImageSize
= FsGetFileSize(Image
);
606 /* Set the file pointer to zero */
607 FsSetFilePointer(Image
, 0);
609 /* Allocate a temporary buffer for the read */
610 ReadBuffer
= MmAllocateMemory(ImageSize
);
612 /* Load the file image */
613 FsReadFile(Image
, ImageSize
, NULL
, ReadBuffer
);
615 /* Map it into virtual memory */
616 ImageSize
= FrLdrReMapImage(ReadBuffer
, LoadBase
);
618 /* Free the temporary buffer */
619 MmFreeMemory(ReadBuffer
);
621 /* Calculate Difference between Real Base and Compiled Base*/
622 Status
= LdrRelocateImageWithBias(LoadBase
,
623 (ULONG_PTR
)ImageBase
-
628 STATUS_UNSUCCESSFUL
);
629 if (!NT_SUCCESS(Status
))
632 DbgPrint("Failed to relocate image: %s\n", Name
);
636 /* Fill out Module Data Structure */
637 reactos_modules
[ImageId
].ModStart
= (ULONG_PTR
)ImageBase
;
638 reactos_modules
[ImageId
].ModEnd
= (ULONG_PTR
)ImageBase
+ ImageSize
;
639 strcpy(reactos_module_strings
[ImageId
], Name
);
640 reactos_modules
[ImageId
].String
= (ULONG_PTR
)reactos_module_strings
[ImageId
];
641 LoaderBlock
.ModsCount
++;
643 /* Increase the next Load Base */
644 NextModuleBase
= ROUND_UP(NextModuleBase
+ ImageSize
, PAGE_SIZE
);
646 /* Load HAL if this is the kernel */
647 if (ImageType
== 1) FrLdrLoadImage("hal.dll", 10, FALSE
);
649 /* Perform import fixups */
650 LdrPEFixupImports(LoadBase
, Name
);
652 /* Return the final mapped address */
658 FrLdrLoadModule(FILE *ModuleImage
,
662 ULONG LocalModuleSize
;
663 PLOADER_MODULE ModuleData
;
667 /* Get current module data structure and module name string array */
668 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
670 /* Get only the Module Name */
673 TempName
= strchr(ModuleName
, '\\');
676 ModuleName
= TempName
+ 1;
680 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
682 /* Get Module Size */
683 LocalModuleSize
= FsGetFileSize(ModuleImage
);
685 /* Fill out Module Data Structure */
686 ModuleData
->ModStart
= NextModuleBase
;
687 ModuleData
->ModEnd
= NextModuleBase
+ LocalModuleSize
;
690 strcpy(NameBuffer
, ModuleName
);
691 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
693 /* Load the file image */
694 FsReadFile(ModuleImage
, LocalModuleSize
, NULL
, (PVOID
)NextModuleBase
);
696 /* Move to next memory block and increase Module Count */
697 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
698 LoaderBlock
.ModsCount
++;
699 // DbgPrint("NextBase, ImageSize, ModStart, ModEnd %p %p %p %p\n",
700 // NextModuleBase, LocalModuleSize, ModuleData->ModStart, ModuleData->ModEnd);
702 /* Return Module Size if required */
703 if (ModuleSize
!= NULL
) {
704 *ModuleSize
= LocalModuleSize
;
707 return(ModuleData
->ModStart
);
712 FrLdrCreateModule(LPCSTR ModuleName
)
714 PLOADER_MODULE ModuleData
;
717 /* Get current module data structure and module name string array */
718 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
719 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
721 /* Set up the structure */
722 ModuleData
->ModStart
= NextModuleBase
;
723 ModuleData
->ModEnd
= -1;
726 strcpy(NameBuffer
, ModuleName
);
727 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
729 /* Set the current Module */
730 CurrentModule
= ModuleData
;
732 /* Return Module Base Address */
733 return(ModuleData
->ModStart
);
738 FrLdrCloseModule(ULONG_PTR ModuleBase
,
741 PLOADER_MODULE ModuleData
= CurrentModule
;
743 /* Make sure a module is opened */
746 /* Make sure this is the right module and that it hasn't been closed */
747 if ((ModuleBase
== ModuleData
->ModStart
) && (ModuleData
->ModEnd
== (ULONG_PTR
)-1)) {
749 /* Close the Module */
750 ModuleData
->ModEnd
= ModuleData
->ModStart
+ ModuleSize
;
752 /* Set the next Module Base and increase the number of modules */
753 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
754 LoaderBlock
.ModsCount
++;
756 /* Close the currently opened module */
757 CurrentModule
= NULL
;