2 * COPYRIGHT: See COPYING in the top level directory
4 * FILE: boot/freeldr/freeldr/multiboot.c
5 * PURPOSE: ReactOS Loader
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Hartmut Birr - SMP/PAE Code
11 #include <internal/i386/ke.h>
16 /* Base Addres of Kernel in Physical Memory */
17 #define KERNEL_BASE_PHYS 0x200000
19 /* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
22 /* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
24 #define PDE_SHIFT_PAE 18
27 /* Converts a Relative Address read from the Kernel into a Physical Address */
29 (ULONG_PTR)((ULONG_PTR)p + KERNEL_BASE_PHYS)
31 /* Converts a Phsyical Address Pointer into a Page Frame Number */
32 #define PaPtrToPfn(p) \
33 (((ULONG_PTR)&p) >> PFN_SHIFT)
35 /* Converts a Phsyical Address into a Page Frame Number */
39 #define STARTUP_BASE 0xF0000000
40 #define HYPERSPACE_BASE 0xF0800000
41 #define APIC_BASE 0xFEC00000
42 #define KPCR_BASE 0xFF000000
44 #define LowMemPageTableIndex 0
45 #define StartupPageTableIndex (STARTUP_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
46 #define HyperspacePageTableIndex (HYPERSPACE_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
47 #define KpcrPageTableIndex (KPCR_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
48 #define ApicPageTableIndex (APIC_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
50 #define LowMemPageTableIndexPae 0
51 #define StartupPageTableIndexPae (STARTUP_BASE >> 21)
52 #define HyperspacePageTableIndexPae (HYPERSPACE_BASE >> 21)
53 #define KpcrPageTableIndexPae (KPCR_BASE >> 21)
54 #define ApicPageTableIndexPae (APIC_BASE >> 21)
57 #define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase
59 /* Load Address of Next Module */
60 ULONG_PTR NextModuleBase
= 0;
62 /* Currently Opened Module */
63 PFRLDR_MODULE CurrentModule
= NULL
;
65 /* Unrelocated Kernel Base in Virtual Memory */
68 /* Wether PAE is to be used or not */
69 BOOLEAN PaeModeEnabled
;
71 /* Kernel Entrypoint in Physical Memory */
72 ULONG_PTR KernelEntry
;
74 /* Page Directory and Tables for non-PAE Systems */
75 extern ULONG_PTR startup_pagedirectory
;
76 extern ULONG_PTR lowmem_pagetable
;
77 extern ULONG_PTR kernel_pagetable
;
78 extern ULONG_PTR hyperspace_pagetable
;
79 extern ULONG_PTR _pae_pagedirtable
;
80 extern ULONG_PTR apic_pagetable
;
81 extern ULONG_PTR kpcr_pagetable
;
83 /* Page Directory and Tables for PAE Systems */
84 extern ULONG_PTR startup_pagedirectorytable_pae
;
85 extern ULONG_PTR startup_pagedirectory_pae
;
86 extern ULONG_PTR lowmem_pagetable_pae
;
87 extern ULONG_PTR kernel_pagetable_pae
;
88 extern ULONG_PTR hyperspace_pagetable_pae
;
89 extern ULONG_PTR pagedirtable_pae
;
90 extern ULONG_PTR apic_pagetable_pae
;
91 extern ULONG_PTR kpcr_pagetable_pae
;
93 typedef struct _HARDWARE_PTE_X86
{
97 ULONG WriteThrough
: 1;
98 ULONG CacheDisable
: 1;
103 ULONG CopyOnWrite
: 1;
106 ULONG PageFrameNumber
: 20;
107 } HARDWARE_PTE_X86
, *PHARDWARE_PTE_X86
;
109 typedef struct _HARDWARE_PTE_X64
{
113 ULONG WriteThrough
: 1;
114 ULONG CacheDisable
: 1;
119 ULONG CopyOnWrite
: 1;
122 ULONG PageFrameNumber
: 20;
123 ULONG reserved2
: 31;
125 } HARDWARE_PTE_X64
, *PHARDWARE_PTE_X64
;
127 typedef struct _PAGE_DIRECTORY_X86
{
128 HARDWARE_PTE_X86 Pde
[1024];
129 } PAGE_DIRECTORY_x86
, *PPAGE_DIRECTORY_X86
;
131 typedef struct _PAGE_DIRECTORY_X64
{
132 HARDWARE_PTE_X64 Pde
[2048];
133 } PAGE_DIRECTORY_X64
, *PPAGE_DIRECTORY_X64
;
135 typedef struct _PAGE_DIRECTORY_TABLE_X64
{
136 HARDWARE_PTE_X64 Pde
[4];
137 } PAGE_DIRECTORY_TABLE_X64
, *PPAGE_DIRECTORY_TABLE_X64
;
139 /* FUNCTIONS *****************************************************************/
145 * Prepares the system for loading the Kernel.
148 * Magic - Multiboot Magic
159 FrLdrStartup(ULONG Magic
)
161 /* Disable Interrupts */
162 Ke386DisableInterrupts();
164 /* Re-initalize EFLAGS */
167 /* Get Kernel Base and Set MmSystemRangeStart */
168 FrLdrGetKernelBase();
172 /* Initialize the page directory */
173 FrLdrSetupPageDirectory();
175 /* Initialize Paging, Write-Protection and Load NTOSKRNL */
176 FrLdrSetupPae(Magic
);
183 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
187 * Magic - Multiboot Magic
198 FrLdrSetupPae(ULONG Magic
)
200 ULONG_PTR PageDirectoryBaseAddress
= (ULONG_PTR
)&startup_pagedirectory
;
205 PageDirectoryBaseAddress
= (ULONG_PTR
)&startup_pagedirectorytable_pae
;
208 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PAE
);
212 Ke386SetPageTableDirectory(PageDirectoryBaseAddress
);
214 /* Enable Paging and Write Protect*/
215 Ke386SetCr0(Ke386GetCr0() | X86_CR0_PG
| X86_CR0_WP
);
218 PagedJump
= (ASMCODE
)KernelEntryPoint
;
219 PagedJump(Magic
, &LoaderBlock
);
226 * Gets the Kernel Base to use.
234 * Sets both the FreeLdr internal variable as well as the one which
235 * will be used by the Kernel.
240 FrLdrGetKernelBase(VOID
)
244 /* Read Command Line */
245 p
= (PCHAR
)LoaderBlock
.CommandLine
;
246 while ((p
= strchr(p
, '/')) != NULL
) {
249 if (!strnicmp(p
+ 1, "3GB", 3)) {
251 /* Make sure there's nothing following it */
252 if (p
[4] == ' ' || p
[4] == 0) {
255 KernelBase
= 0xC0000000;
263 LoaderBlock
.KernelBase
= KernelBase
;
270 * Determines whether PAE mode shoudl be enabled or not.
284 FrLdrGetPaeMode(VOID
)
286 /* FIXME: Read command line */
287 PaeModeEnabled
= FALSE
;
295 * FrLdrSetupPageDirectory
298 * Sets up the ReactOS Startup Page Directory.
307 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
308 * As such, please note that PageFrameNumber == PageEntryNumber.
313 FrLdrSetupPageDirectory(VOID
)
315 PPAGE_DIRECTORY_X86 PageDir
;
316 PPAGE_DIRECTORY_TABLE_X64 PageDirTablePae
;
317 PPAGE_DIRECTORY_X64 PageDirPae
;
318 ULONG KernelPageTableIndex
;
321 if (PaeModeEnabled
) {
323 /* Get the Kernel Table Index */
324 KernelPageTableIndex
= (KernelBase
>> 21);
326 /* Get the Startup Page Directory Table */
327 PageDirTablePae
= (PPAGE_DIRECTORY_TABLE_X64
)&startup_pagedirectorytable_pae
;
329 /* Get the Startup Page Directory */
330 PageDirPae
= (PPAGE_DIRECTORY_X64
)&startup_pagedirectory_pae
;
332 /* Set the Startup page directory table */
333 for (i
= 0; i
< 4; i
++)
335 PageDirTablePae
->Pde
[i
].Valid
= 1;
336 PageDirTablePae
->Pde
[i
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory_pae
) + i
;
339 /* Set up the Low Memory PDE */
340 for (i
= 0; i
< 2; i
++)
342 PageDirPae
->Pde
[LowMemPageTableIndexPae
+ i
].Valid
= 1;
343 PageDirPae
->Pde
[LowMemPageTableIndexPae
+ i
].Write
= 1;
344 PageDirPae
->Pde
[LowMemPageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(lowmem_pagetable_pae
) + i
;
347 /* Set up the Kernel PDEs */
348 for (i
= 0; i
< 3; i
++)
350 PageDirPae
->Pde
[KernelPageTableIndex
+ i
].Valid
= 1;
351 PageDirPae
->Pde
[KernelPageTableIndex
+ i
].Write
= 1;
352 PageDirPae
->Pde
[KernelPageTableIndex
+ i
].PageFrameNumber
= PaPtrToPfn(kernel_pagetable_pae
) + i
;
355 /* Set up the Startup PDE */
356 for (i
= 0; i
< 4; i
++)
358 PageDirPae
->Pde
[StartupPageTableIndexPae
+ i
].Valid
= 1;
359 PageDirPae
->Pde
[StartupPageTableIndexPae
+ i
].Write
= 1;
360 PageDirPae
->Pde
[StartupPageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory_pae
) + i
;
363 /* Set up the Hyperspace PDE */
364 for (i
= 0; i
< 2; i
++)
366 PageDirPae
->Pde
[HyperspacePageTableIndexPae
+ i
].Valid
= 1;
367 PageDirPae
->Pde
[HyperspacePageTableIndexPae
+ i
].Write
= 1;
368 PageDirPae
->Pde
[HyperspacePageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(hyperspace_pagetable_pae
) + i
;
371 /* Set up the Apic PDE */
372 for (i
= 0; i
< 2; i
++)
374 PageDirPae
->Pde
[ApicPageTableIndexPae
+ i
].Valid
= 1;
375 PageDirPae
->Pde
[ApicPageTableIndexPae
+ i
].Write
= 1;
376 PageDirPae
->Pde
[ApicPageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(apic_pagetable_pae
) + i
;
379 /* Set up the KPCR PDE */
380 PageDirPae
->Pde
[KpcrPageTableIndexPae
].Valid
= 1;
381 PageDirPae
->Pde
[KpcrPageTableIndexPae
].Write
= 1;
382 PageDirPae
->Pde
[KpcrPageTableIndexPae
].PageFrameNumber
= PaPtrToPfn(kpcr_pagetable_pae
);
384 /* Set up Low Memory PTEs */
385 PageDirPae
= (PPAGE_DIRECTORY_X64
)&lowmem_pagetable_pae
;
386 for (i
=0; i
<1024; i
++) {
388 PageDirPae
->Pde
[i
].Valid
= 1;
389 PageDirPae
->Pde
[i
].Write
= 1;
390 PageDirPae
->Pde
[i
].Owner
= 1;
391 PageDirPae
->Pde
[i
].PageFrameNumber
= i
;
394 /* Set up Kernel PTEs */
395 PageDirPae
= (PPAGE_DIRECTORY_X64
)&kernel_pagetable_pae
;
396 for (i
=0; i
<1536; i
++) {
398 PageDirPae
->Pde
[i
].Valid
= 1;
399 PageDirPae
->Pde
[i
].Write
= 1;
400 PageDirPae
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
) + i
;
403 /* Set up APIC PTEs */
404 PageDirPae
= (PPAGE_DIRECTORY_X64
)&apic_pagetable_pae
;
405 PageDirPae
->Pde
[0].Valid
= 1;
406 PageDirPae
->Pde
[0].Write
= 1;
407 PageDirPae
->Pde
[0].CacheDisable
= 1;
408 PageDirPae
->Pde
[0].WriteThrough
= 1;
409 PageDirPae
->Pde
[0].PageFrameNumber
= PaToPfn(APIC_BASE
);
410 PageDirPae
->Pde
[0x200].Valid
= 1;
411 PageDirPae
->Pde
[0x200].Write
= 1;
412 PageDirPae
->Pde
[0x200].CacheDisable
= 1;
413 PageDirPae
->Pde
[0x200].WriteThrough
= 1;
414 PageDirPae
->Pde
[0x200].PageFrameNumber
= PaToPfn(APIC_BASE
+ KERNEL_BASE_PHYS
);
416 /* Set up KPCR PTEs */
417 PageDirPae
= (PPAGE_DIRECTORY_X64
)&kpcr_pagetable_pae
;
418 PageDirPae
->Pde
[0].Valid
= 1;
419 PageDirPae
->Pde
[0].Write
= 1;
420 PageDirPae
->Pde
[0].PageFrameNumber
= 1;
424 /* Get the Kernel Table Index */
425 KernelPageTableIndex
= (KernelBase
>> PDE_SHIFT
) / sizeof(HARDWARE_PTE_X86
);
427 /* Get the Startup Page Directory */
428 PageDir
= (PPAGE_DIRECTORY_X86
)&startup_pagedirectory
;
430 /* Set up the Low Memory PDE */
431 PageDir
->Pde
[LowMemPageTableIndex
].Valid
= 1;
432 PageDir
->Pde
[LowMemPageTableIndex
].Write
= 1;
433 PageDir
->Pde
[LowMemPageTableIndex
].PageFrameNumber
= PaPtrToPfn(lowmem_pagetable
);
435 /* Set up the Kernel PDEs */
436 PageDir
->Pde
[KernelPageTableIndex
].Valid
= 1;
437 PageDir
->Pde
[KernelPageTableIndex
].Write
= 1;
438 PageDir
->Pde
[KernelPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
);
439 PageDir
->Pde
[KernelPageTableIndex
+ 1].Valid
= 1;
440 PageDir
->Pde
[KernelPageTableIndex
+ 1].Write
= 1;
441 PageDir
->Pde
[KernelPageTableIndex
+ 1].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
+ 4096);
443 /* Set up the Startup PDE */
444 PageDir
->Pde
[StartupPageTableIndex
].Valid
= 1;
445 PageDir
->Pde
[StartupPageTableIndex
].Write
= 1;
446 PageDir
->Pde
[StartupPageTableIndex
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory
);
448 /* Set up the Hyperspace PDE */
449 PageDir
->Pde
[HyperspacePageTableIndex
].Valid
= 1;
450 PageDir
->Pde
[HyperspacePageTableIndex
].Write
= 1;
451 PageDir
->Pde
[HyperspacePageTableIndex
].PageFrameNumber
= PaPtrToPfn(hyperspace_pagetable
);
453 /* Set up the Apic PDE */
454 PageDir
->Pde
[ApicPageTableIndex
].Valid
= 1;
455 PageDir
->Pde
[ApicPageTableIndex
].Write
= 1;
456 PageDir
->Pde
[ApicPageTableIndex
].PageFrameNumber
= PaPtrToPfn(apic_pagetable
);
458 /* Set up the KPCR PDE */
459 PageDir
->Pde
[KpcrPageTableIndex
].Valid
= 1;
460 PageDir
->Pde
[KpcrPageTableIndex
].Write
= 1;
461 PageDir
->Pde
[KpcrPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kpcr_pagetable
);
463 /* Set up Low Memory PTEs */
464 PageDir
= (PPAGE_DIRECTORY_X86
)&lowmem_pagetable
;
465 for (i
=0; i
<1024; i
++) {
467 PageDir
->Pde
[i
].Valid
= 1;
468 PageDir
->Pde
[i
].Write
= 1;
469 PageDir
->Pde
[i
].Owner
= 1;
470 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(i
* PAGE_SIZE
);
473 /* Set up Kernel PTEs */
474 PageDir
= (PPAGE_DIRECTORY_X86
)&kernel_pagetable
;
475 for (i
=0; i
<1536; i
++) {
477 PageDir
->Pde
[i
].Valid
= 1;
478 PageDir
->Pde
[i
].Write
= 1;
479 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
+ i
* PAGE_SIZE
);
482 /* Set up APIC PTEs */
483 PageDir
= (PPAGE_DIRECTORY_X86
)&apic_pagetable
;
484 PageDir
->Pde
[0].Valid
= 1;
485 PageDir
->Pde
[0].Write
= 1;
486 PageDir
->Pde
[0].CacheDisable
= 1;
487 PageDir
->Pde
[0].WriteThrough
= 1;
488 PageDir
->Pde
[0].PageFrameNumber
= PaToPfn(APIC_BASE
);
489 PageDir
->Pde
[0x200].Valid
= 1;
490 PageDir
->Pde
[0x200].Write
= 1;
491 PageDir
->Pde
[0x200].CacheDisable
= 1;
492 PageDir
->Pde
[0x200].WriteThrough
= 1;
493 PageDir
->Pde
[0x200].PageFrameNumber
= PaToPfn(APIC_BASE
+ KERNEL_BASE_PHYS
);
495 /* Set up KPCR PTEs */
496 PageDir
= (PPAGE_DIRECTORY_X86
)&kpcr_pagetable
;
497 PageDir
->Pde
[0].Valid
= 1;
498 PageDir
->Pde
[0].Write
= 1;
499 PageDir
->Pde
[0].PageFrameNumber
= 1;
508 * Maps the Kernel into memory, does PE Section Mapping, initalizes the
509 * uninitialized data sections, and relocates the image.
512 * KernelImage - FILE Structure representing the ntoskrnl image file.
515 * TRUE if the Kernel was mapped.
523 FrLdrMapKernel(FILE *KernelImage
)
525 PIMAGE_DOS_HEADER ImageHeader
;
526 PIMAGE_NT_HEADERS NtHeader
;
527 PIMAGE_SECTION_HEADER Section
;
530 ULONG_PTR SourceSection
;
531 ULONG_PTR TargetSection
;
535 /* Allocate 1024 bytes for PE Header */
536 ImageHeader
= (PIMAGE_DOS_HEADER
)MmAllocateMemory(1024);
538 /* Make sure it was succesful */
539 if (ImageHeader
== NULL
) {
544 /* Load the first 1024 bytes of the kernel image so we can read the PE header */
545 if (!FsReadFile(KernelImage
, 1024, NULL
, ImageHeader
)) {
547 /* Fail if we couldn't read */
548 MmFreeMemory(ImageHeader
);
552 /* Now read the MZ header to get the offset to the PE Header */
553 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)ImageHeader
+ ImageHeader
->e_lfanew
);
555 /* Save the Image Base */
556 KernelBase
= NtHeader
->OptionalHeader
.ImageBase
;
558 /* Save Entrypoint */
559 KernelEntry
= RaToPa(NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
561 /* Save the Image Size */
562 ImageSize
= NtHeader
->OptionalHeader
.SizeOfImage
;
564 /* Free the Header */
565 MmFreeMemory(ImageHeader
);
567 /* Set the file pointer to zero */
568 FsSetFilePointer(KernelImage
, 0);
570 /* Load the file image */
571 FsReadFile(KernelImage
, ImageSize
, NULL
, (PVOID
)KERNEL_BASE_PHYS
);
573 /* Reload the NT Header */
574 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)KERNEL_BASE_PHYS
+ ImageHeader
->e_lfanew
);
576 /* Load the first section */
577 Section
= IMAGE_FIRST_SECTION(NtHeader
);
578 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
- 1;
580 /* Now go to the last section */
581 Section
+= SectionCount
;
583 /* Walk each section backwards */
584 for (i
=SectionCount
; i
>= 0; i
--, Section
--) {
586 /* Get the disk location and the memory location, and the size */
587 SourceSection
= RaToPa(Section
->PointerToRawData
);
588 TargetSection
= RaToPa(Section
->VirtualAddress
);
589 SectionSize
= Section
->SizeOfRawData
;
591 /* If the section is already mapped correctly, go to the next */
592 if (SourceSection
== TargetSection
) continue;
594 /* Load it into memory */
595 memmove((PVOID
)TargetSection
, (PVOID
)SourceSection
, SectionSize
);
597 /* Check for unitilizated data */
598 if (Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
601 memset((PVOID
)RaToPa(Section
->VirtualAddress
+ Section
->SizeOfRawData
),
603 Section
->Misc
.VirtualSize
- Section
->SizeOfRawData
);
607 /* Now relocate the file */
608 /* FIXME: ADD RELOC CODE */
610 /* Increase the next Load Base */
611 NextModuleBase
= ROUND_UP(KERNEL_BASE_PHYS
+ ImageSize
, PAGE_SIZE
);
619 FrLdrLoadModule(FILE *ModuleImage
,
623 ULONG LocalModuleSize
;
624 PFRLDR_MODULE ModuleData
;
628 /* Get current module data structure and module name string array */
629 ModuleData
= &multiboot_modules
[LoaderBlock
.ModsCount
];
631 /* Get only the Module Name */
634 TempName
= strchr(ModuleName
, '\\');
637 ModuleName
= TempName
+ 1;
641 NameBuffer
= multiboot_module_strings
[LoaderBlock
.ModsCount
];
643 /* Get Module Size */
644 LocalModuleSize
= FsGetFileSize(ModuleImage
);
646 /* Fill out Module Data Structure */
647 ModuleData
->ModuleStart
= NextModuleBase
;
648 ModuleData
->ModuleEnd
= NextModuleBase
+ LocalModuleSize
;
651 strcpy(NameBuffer
, ModuleName
);
652 ModuleData
->ModuleName
= NameBuffer
;
654 /* Load the file image */
655 FsReadFile(ModuleImage
, LocalModuleSize
, NULL
, (PVOID
)NextModuleBase
);
657 /* Move to next memory block and increase Module Count */
658 NextModuleBase
= ROUND_UP(ModuleData
->ModuleEnd
, PAGE_SIZE
);
659 LoaderBlock
.ModsCount
++;
661 /* Return Module Size if required */
662 if (ModuleSize
!= NULL
) {
663 *ModuleSize
= LocalModuleSize
;
666 return(ModuleData
->ModuleStart
);
671 FrLdrCreateModule(LPSTR ModuleName
)
673 PFRLDR_MODULE ModuleData
;
676 /* Get current module data structure and module name string array */
677 ModuleData
= &multiboot_modules
[LoaderBlock
.ModsCount
];
678 NameBuffer
= multiboot_module_strings
[LoaderBlock
.ModsCount
];
680 /* Set up the structure */
681 ModuleData
->ModuleStart
= NextModuleBase
;
682 ModuleData
->ModuleEnd
= -1;
685 strcpy(NameBuffer
, ModuleName
);
686 ModuleData
->ModuleName
= NameBuffer
;
688 /* Set the current Module */
689 CurrentModule
= ModuleData
;
691 /* Return Module Base Address */
692 return(ModuleData
->ModuleStart
);
697 FrLdrCloseModule(ULONG_PTR ModuleBase
,
700 PFRLDR_MODULE ModuleData
= CurrentModule
;
702 /* Make sure a module is opened */
705 /* Make sure this is the right module and that it hasn't been closed */
706 if ((ModuleBase
== ModuleData
->ModuleStart
) && (ModuleData
->ModuleEnd
== -1)) {
708 /* Close the Module */
709 ModuleData
->ModuleEnd
= ModuleData
->ModuleStart
+ ModuleSize
;
711 /* Set the next Module Base and increase the number of modules */
712 NextModuleBase
= ROUND_UP(ModuleData
->ModuleEnd
, PAGE_SIZE
);
713 LoaderBlock
.ModsCount
++;
715 /* Close the currently opened module */
716 CurrentModule
= NULL
;