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)
10 #include <internal/powerpc/ke.h>
15 /* Base Addres of Kernel in Physical Memory */
16 #define KERNEL_BASE_PHYS 0x200000
18 /* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
21 /* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
23 #define PDE_SHIFT_PAE 18
26 /* Converts a Relative Address read from the Kernel into a Physical Address */
28 (ULONG_PTR)((ULONG_PTR)p + KERNEL_BASE_PHYS)
30 /* Converts a Phsyical Address Pointer into a Page Frame Number */
31 #define PaPtrToPfn(p) \
32 (((ULONG_PTR)&p) >> PFN_SHIFT)
34 /* Converts a Phsyical Address into a Page Frame Number */
38 #define STARTUP_BASE 0xF0000000
39 #define HYPERSPACE_BASE 0xF0800000
40 #define APIC_BASE 0xFEC00000
41 #define KPCR_BASE 0xFF000000
43 #define LowMemPageTableIndex 0
44 #define StartupPageTableIndex (STARTUP_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
45 #define HyperspacePageTableIndex (HYPERSPACE_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
46 #define KpcrPageTableIndex (KPCR_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
47 #define ApicPageTableIndex (APIC_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
49 #define LowMemPageTableIndexPae 0
50 #define StartupPageTableIndexPae (STARTUP_BASE >> 21)
51 #define HyperspacePageTableIndexPae (HYPERSPACE_BASE >> 21)
52 #define KpcrPageTableIndexPae (KPCR_BASE >> 21)
53 #define ApicPageTableIndexPae (APIC_BASE >> 21)
56 #define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase
58 /* Load Address of Next Module */
59 ULONG_PTR NextModuleBase
= 0;
61 /* Currently Opened Module */
62 VOID
*CurrentModule
= NULL
;
64 /* Unrelocated Kernel Base in Virtual Memory */
67 /* Wether PAE is to be used or not */
68 BOOLEAN PaeModeEnabled
;
70 /* Kernel Entrypoint in Physical Memory */
71 ULONG_PTR KernelEntry
;
73 /* FUNCTIONS *****************************************************************/
79 * Prepares the system for loading the Kernel.
82 * Magic - Multiboot Magic
93 FrLdrStartup(ULONG Magic
)
96 /* Disable Interrupts */
97 KeArchDisableInterrupts();
99 /* Re-initalize EFLAGS */
102 /* Initialize the page directory */
103 FrLdrSetupPageDirectory();
111 * Gets the Kernel Base to use.
119 * Sets both the FreeLdr internal variable as well as the one which
120 * will be used by the Kernel.
125 FrLdrGetKernelBase(VOID
)
129 /* Read Command Line */
130 p
= (PCHAR
)LoaderBlock
.CommandLine
;
131 while ((p
= strchr(p
, '/')) != NULL
) {
134 if (!strnicmp(p
+ 1, "3GB", 3)) {
136 /* Make sure there's nothing following it */
137 if (p
[4] == ' ' || p
[4] == 0) {
140 KernelBase
= 0xC0000000;
148 LoaderBlock
.KernelBase
= KernelBase
;
152 * FrLdrSetupPageDirectory
155 * Sets up the ReactOS Startup Page Directory.
164 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
165 * As such, please note that PageFrameNumber == PageEntryNumber.
170 FrLdrSetupPageDirectory(VOID
)
173 PPAGE_DIRECTORY_X86 PageDir
;
174 PPAGE_DIRECTORY_TABLE_X64 PageDirTablePae
;
175 PPAGE_DIRECTORY_X64 PageDirPae
;
176 ULONG KernelPageTableIndex
;
179 if (PaeModeEnabled
) {
181 /* Get the Kernel Table Index */
182 KernelPageTableIndex
= (KernelBase
>> 21);
184 /* Get the Startup Page Directory Table */
185 PageDirTablePae
= (PPAGE_DIRECTORY_TABLE_X64
)&startup_pagedirectorytable_pae
;
187 /* Get the Startup Page Directory */
188 PageDirPae
= (PPAGE_DIRECTORY_X64
)&startup_pagedirectory_pae
;
190 /* Set the Startup page directory table */
191 for (i
= 0; i
< 4; i
++)
193 PageDirTablePae
->Pde
[i
].Valid
= 1;
194 PageDirTablePae
->Pde
[i
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory_pae
) + i
;
197 /* Set up the Low Memory PDE */
198 for (i
= 0; i
< 2; i
++)
200 PageDirPae
->Pde
[LowMemPageTableIndexPae
+ i
].Valid
= 1;
201 PageDirPae
->Pde
[LowMemPageTableIndexPae
+ i
].Write
= 1;
202 PageDirPae
->Pde
[LowMemPageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(lowmem_pagetable_pae
) + i
;
205 /* Set up the Kernel PDEs */
206 for (i
= 0; i
< 3; i
++)
208 PageDirPae
->Pde
[KernelPageTableIndex
+ i
].Valid
= 1;
209 PageDirPae
->Pde
[KernelPageTableIndex
+ i
].Write
= 1;
210 PageDirPae
->Pde
[KernelPageTableIndex
+ i
].PageFrameNumber
= PaPtrToPfn(kernel_pagetable_pae
) + i
;
213 /* Set up the Startup PDE */
214 for (i
= 0; i
< 4; i
++)
216 PageDirPae
->Pde
[StartupPageTableIndexPae
+ i
].Valid
= 1;
217 PageDirPae
->Pde
[StartupPageTableIndexPae
+ i
].Write
= 1;
218 PageDirPae
->Pde
[StartupPageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory_pae
) + i
;
221 /* Set up the Hyperspace PDE */
222 for (i
= 0; i
< 2; i
++)
224 PageDirPae
->Pde
[HyperspacePageTableIndexPae
+ i
].Valid
= 1;
225 PageDirPae
->Pde
[HyperspacePageTableIndexPae
+ i
].Write
= 1;
226 PageDirPae
->Pde
[HyperspacePageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(hyperspace_pagetable_pae
) + i
;
229 /* Set up the Apic PDE */
230 for (i
= 0; i
< 2; i
++)
232 PageDirPae
->Pde
[ApicPageTableIndexPae
+ i
].Valid
= 1;
233 PageDirPae
->Pde
[ApicPageTableIndexPae
+ i
].Write
= 1;
234 PageDirPae
->Pde
[ApicPageTableIndexPae
+ i
].PageFrameNumber
= PaPtrToPfn(apic_pagetable_pae
) + i
;
237 /* Set up the KPCR PDE */
238 PageDirPae
->Pde
[KpcrPageTableIndexPae
].Valid
= 1;
239 PageDirPae
->Pde
[KpcrPageTableIndexPae
].Write
= 1;
240 PageDirPae
->Pde
[KpcrPageTableIndexPae
].PageFrameNumber
= PaPtrToPfn(kpcr_pagetable_pae
);
242 /* Set up Low Memory PTEs */
243 PageDirPae
= (PPAGE_DIRECTORY_X64
)&lowmem_pagetable_pae
;
244 for (i
=0; i
<1024; i
++) {
246 PageDirPae
->Pde
[i
].Valid
= 1;
247 PageDirPae
->Pde
[i
].Write
= 1;
248 PageDirPae
->Pde
[i
].Owner
= 1;
249 PageDirPae
->Pde
[i
].PageFrameNumber
= i
;
252 /* Set up Kernel PTEs */
253 PageDirPae
= (PPAGE_DIRECTORY_X64
)&kernel_pagetable_pae
;
254 for (i
=0; i
<1536; i
++) {
256 PageDirPae
->Pde
[i
].Valid
= 1;
257 PageDirPae
->Pde
[i
].Write
= 1;
258 PageDirPae
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
) + i
;
261 /* Set up APIC PTEs */
262 PageDirPae
= (PPAGE_DIRECTORY_X64
)&apic_pagetable_pae
;
263 PageDirPae
->Pde
[0].Valid
= 1;
264 PageDirPae
->Pde
[0].Write
= 1;
265 PageDirPae
->Pde
[0].CacheDisable
= 1;
266 PageDirPae
->Pde
[0].WriteThrough
= 1;
267 PageDirPae
->Pde
[0].PageFrameNumber
= PaToPfn(APIC_BASE
);
268 PageDirPae
->Pde
[0x200].Valid
= 1;
269 PageDirPae
->Pde
[0x200].Write
= 1;
270 PageDirPae
->Pde
[0x200].CacheDisable
= 1;
271 PageDirPae
->Pde
[0x200].WriteThrough
= 1;
272 PageDirPae
->Pde
[0x200].PageFrameNumber
= PaToPfn(APIC_BASE
+ KERNEL_BASE_PHYS
);
274 /* Set up KPCR PTEs */
275 PageDirPae
= (PPAGE_DIRECTORY_X64
)&kpcr_pagetable_pae
;
276 PageDirPae
->Pde
[0].Valid
= 1;
277 PageDirPae
->Pde
[0].Write
= 1;
278 PageDirPae
->Pde
[0].PageFrameNumber
= 1;
282 /* Get the Kernel Table Index */
283 KernelPageTableIndex
= (KernelBase
>> PDE_SHIFT
) / sizeof(HARDWARE_PTE_X86
);
285 /* Get the Startup Page Directory */
286 PageDir
= (PPAGE_DIRECTORY_X86
)&startup_pagedirectory
;
288 /* Set up the Low Memory PDE */
289 PageDir
->Pde
[LowMemPageTableIndex
].Valid
= 1;
290 PageDir
->Pde
[LowMemPageTableIndex
].Write
= 1;
291 PageDir
->Pde
[LowMemPageTableIndex
].PageFrameNumber
= PaPtrToPfn(lowmem_pagetable
);
293 /* Set up the Kernel PDEs */
294 PageDir
->Pde
[KernelPageTableIndex
].Valid
= 1;
295 PageDir
->Pde
[KernelPageTableIndex
].Write
= 1;
296 PageDir
->Pde
[KernelPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
);
297 PageDir
->Pde
[KernelPageTableIndex
+ 1].Valid
= 1;
298 PageDir
->Pde
[KernelPageTableIndex
+ 1].Write
= 1;
299 PageDir
->Pde
[KernelPageTableIndex
+ 1].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
+ 4096);
301 /* Set up the Startup PDE */
302 PageDir
->Pde
[StartupPageTableIndex
].Valid
= 1;
303 PageDir
->Pde
[StartupPageTableIndex
].Write
= 1;
304 PageDir
->Pde
[StartupPageTableIndex
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory
);
306 /* Set up the Hyperspace PDE */
307 PageDir
->Pde
[HyperspacePageTableIndex
].Valid
= 1;
308 PageDir
->Pde
[HyperspacePageTableIndex
].Write
= 1;
309 PageDir
->Pde
[HyperspacePageTableIndex
].PageFrameNumber
= PaPtrToPfn(hyperspace_pagetable
);
311 /* Set up the Apic PDE */
312 PageDir
->Pde
[ApicPageTableIndex
].Valid
= 1;
313 PageDir
->Pde
[ApicPageTableIndex
].Write
= 1;
314 PageDir
->Pde
[ApicPageTableIndex
].PageFrameNumber
= PaPtrToPfn(apic_pagetable
);
316 /* Set up the KPCR PDE */
317 PageDir
->Pde
[KpcrPageTableIndex
].Valid
= 1;
318 PageDir
->Pde
[KpcrPageTableIndex
].Write
= 1;
319 PageDir
->Pde
[KpcrPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kpcr_pagetable
);
321 /* Set up Low Memory PTEs */
322 PageDir
= (PPAGE_DIRECTORY_X86
)&lowmem_pagetable
;
323 for (i
=0; i
<1024; i
++) {
325 PageDir
->Pde
[i
].Valid
= 1;
326 PageDir
->Pde
[i
].Write
= 1;
327 PageDir
->Pde
[i
].Owner
= 1;
328 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(i
* PAGE_SIZE
);
331 /* Set up Kernel PTEs */
332 PageDir
= (PPAGE_DIRECTORY_X86
)&kernel_pagetable
;
333 for (i
=0; i
<1536; i
++) {
335 PageDir
->Pde
[i
].Valid
= 1;
336 PageDir
->Pde
[i
].Write
= 1;
337 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
+ i
* PAGE_SIZE
);
340 /* Set up APIC PTEs */
341 PageDir
= (PPAGE_DIRECTORY_X86
)&apic_pagetable
;
342 PageDir
->Pde
[0].Valid
= 1;
343 PageDir
->Pde
[0].Write
= 1;
344 PageDir
->Pde
[0].CacheDisable
= 1;
345 PageDir
->Pde
[0].WriteThrough
= 1;
346 PageDir
->Pde
[0].PageFrameNumber
= PaToPfn(APIC_BASE
);
347 PageDir
->Pde
[0x200].Valid
= 1;
348 PageDir
->Pde
[0x200].Write
= 1;
349 PageDir
->Pde
[0x200].CacheDisable
= 1;
350 PageDir
->Pde
[0x200].WriteThrough
= 1;
351 PageDir
->Pde
[0x200].PageFrameNumber
= PaToPfn(APIC_BASE
+ KERNEL_BASE_PHYS
);
353 /* Set up KPCR PTEs */
354 PageDir
= (PPAGE_DIRECTORY_X86
)&kpcr_pagetable
;
355 PageDir
->Pde
[0].Valid
= 1;
356 PageDir
->Pde
[0].Write
= 1;
357 PageDir
->Pde
[0].PageFrameNumber
= 1;
367 * Maps the Kernel into memory, does PE Section Mapping, initalizes the
368 * uninitialized data sections, and relocates the image.
371 * KernelImage - FILE Structure representing the ntoskrnl image file.
374 * TRUE if the Kernel was mapped.
382 FrLdrMapKernel(FILE *KernelImage
)
385 PIMAGE_DOS_HEADER ImageHeader
;
386 PIMAGE_NT_HEADERS NtHeader
;
387 PIMAGE_SECTION_HEADER Section
;
390 ULONG_PTR SourceSection
;
391 ULONG_PTR TargetSection
;
394 PIMAGE_DATA_DIRECTORY RelocationDDir
;
395 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
397 ULONG_PTR Address
, MaxAddress
;
403 /* Allocate 1024 bytes for PE Header */
404 ImageHeader
= (PIMAGE_DOS_HEADER
)MmAllocateMemory(1024);
406 /* Make sure it was succesful */
407 if (ImageHeader
== NULL
) {
412 /* Load the first 1024 bytes of the kernel image so we can read the PE header */
413 if (!FsReadFile(KernelImage
, 1024, NULL
, ImageHeader
)) {
415 /* Fail if we couldn't read */
416 MmFreeMemory(ImageHeader
);
420 /* Now read the MZ header to get the offset to the PE Header */
421 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)ImageHeader
+ ImageHeader
->e_lfanew
);
423 /* Get Kernel Base */
424 KernelBase
= NtHeader
->OptionalHeader
.ImageBase
;
425 FrLdrGetKernelBase();
427 /* Save Entrypoint */
428 KernelEntry
= RaToPa(NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
430 /* Save the Image Size */
431 ImageSize
= NtHeader
->OptionalHeader
.SizeOfImage
;
433 /* Free the Header */
434 MmFreeMemory(ImageHeader
);
436 /* Set the file pointer to zero */
437 FsSetFilePointer(KernelImage
, 0);
439 /* Load the file image */
440 FsReadFile(KernelImage
, ImageSize
, NULL
, (PVOID
)KERNEL_BASE_PHYS
);
442 /* Reload the NT Header */
443 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)KERNEL_BASE_PHYS
+ ImageHeader
->e_lfanew
);
445 /* Load the first section */
446 Section
= IMAGE_FIRST_SECTION(NtHeader
);
447 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
- 1;
449 /* Now go to the last section */
450 Section
+= SectionCount
;
452 /* Walk each section backwards */
453 for (i
=SectionCount
; i
>= 0; i
--, Section
--) {
455 /* Get the disk location and the memory location, and the size */
456 SourceSection
= RaToPa(Section
->PointerToRawData
);
457 TargetSection
= RaToPa(Section
->VirtualAddress
);
458 SectionSize
= Section
->SizeOfRawData
;
460 /* If the section is already mapped correctly, go to the next */
461 if (SourceSection
== TargetSection
) continue;
463 /* Load it into memory */
464 memmove((PVOID
)TargetSection
, (PVOID
)SourceSection
, SectionSize
);
466 /* Check for unitilizated data */
467 if (Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
470 memset((PVOID
)RaToPa(Section
->VirtualAddress
+ Section
->SizeOfRawData
),
472 Section
->Misc
.VirtualSize
- Section
->SizeOfRawData
);
476 /* Get the Relocation Data Directory */
477 RelocationDDir
= &NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
479 /* Get the Relocation Section Start and End*/
480 RelocationDir
= (PIMAGE_BASE_RELOCATION
)(KERNEL_BASE_PHYS
+ RelocationDDir
->VirtualAddress
);
481 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)RelocationDir
+ RelocationDDir
->Size
);
483 /* Calculate Difference between Real Base and Compiled Base*/
484 Delta
= KernelBase
- NtHeader
->OptionalHeader
.ImageBase
;;
486 /* Determine how far we shoudl relocate */
487 MaxAddress
= KERNEL_BASE_PHYS
+ ImageSize
;
489 /* Relocate until we've processed all the blocks */
490 while (RelocationDir
< RelocationEnd
&& RelocationDir
->SizeOfBlock
> 0) {
492 /* See how many Relocation Blocks we have */
493 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) / sizeof(USHORT
);
495 /* Calculate the Address of this Directory */
496 Address
= KERNEL_BASE_PHYS
+ RelocationDir
->VirtualAddress
;
498 /* Calculate the Offset of the Type */
499 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
501 for (i
= 0; i
< Count
; i
++) {
503 ShortPtr
= (PUSHORT
)(Address
+ (*TypeOffset
& 0xFFF));
505 /* Don't relocate after the end of the loaded driver */
506 if ((ULONG_PTR
)ShortPtr
>= MaxAddress
) break;
508 switch (*TypeOffset
>> 12) {
510 case IMAGE_REL_BASED_ABSOLUTE
:
513 case IMAGE_REL_BASED_HIGH
:
514 *ShortPtr
+= HIWORD(Delta
);
517 case IMAGE_REL_BASED_LOW
:
518 *ShortPtr
+= LOWORD(Delta
);
521 case IMAGE_REL_BASED_HIGHLOW
:
522 LongPtr
= (PULONG
)ShortPtr
;
530 /* Move to the next Relocation Table */
531 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)RelocationDir
+ RelocationDir
->SizeOfBlock
);
534 /* Increase the next Load Base */
535 NextModuleBase
= ROUND_UP(KERNEL_BASE_PHYS
+ ImageSize
, PAGE_SIZE
);
544 FrLdrLoadModule(FILE *ModuleImage
,
549 ULONG LocalModuleSize
;
550 PFRLDR_MODULE ModuleData
;
554 /* Get current module data structure and module name string array */
555 ModuleData
= &multiboot_modules
[LoaderBlock
.ModsCount
];
557 /* Get only the Module Name */
560 TempName
= strchr(ModuleName
, '\\');
563 ModuleName
= TempName
+ 1;
567 NameBuffer
= multiboot_module_strings
[LoaderBlock
.ModsCount
];
569 /* Get Module Size */
570 LocalModuleSize
= FsGetFileSize(ModuleImage
);
572 /* Fill out Module Data Structure */
573 ModuleData
->ModuleStart
= NextModuleBase
;
574 ModuleData
->ModuleEnd
= NextModuleBase
+ LocalModuleSize
;
577 strcpy(NameBuffer
, ModuleName
);
578 ModuleData
->ModuleName
= NameBuffer
;
580 /* Load the file image */
581 FsReadFile(ModuleImage
, LocalModuleSize
, NULL
, (PVOID
)NextModuleBase
);
583 /* Move to next memory block and increase Module Count */
584 NextModuleBase
= ROUND_UP(ModuleData
->ModuleEnd
, PAGE_SIZE
);
585 LoaderBlock
.ModsCount
++;
587 /* Return Module Size if required */
588 if (ModuleSize
!= NULL
) {
589 *ModuleSize
= LocalModuleSize
;
592 return(ModuleData
->ModuleStart
);
600 FrLdrCreateModule(LPCSTR ModuleName
)
603 PFRLDR_MODULE ModuleData
;
606 /* Get current module data structure and module name string array */
607 ModuleData
= &multiboot_modules
[LoaderBlock
.ModsCount
];
608 NameBuffer
= multiboot_module_strings
[LoaderBlock
.ModsCount
];
610 /* Set up the structure */
611 ModuleData
->ModuleStart
= NextModuleBase
;
612 ModuleData
->ModuleEnd
= -1;
615 strcpy(NameBuffer
, ModuleName
);
616 ModuleData
->ModuleName
= NameBuffer
;
618 /* Set the current Module */
619 CurrentModule
= ModuleData
;
621 /* Return Module Base Address */
622 return(ModuleData
->ModuleStart
);
630 FrLdrCloseModule(ULONG_PTR ModuleBase
,
634 PFRLDR_MODULE ModuleData
= CurrentModule
;
636 /* Make sure a module is opened */
639 /* Make sure this is the right module and that it hasn't been closed */
640 if ((ModuleBase
== ModuleData
->ModuleStart
) && (ModuleData
->ModuleEnd
== -1)) {
642 /* Close the Module */
643 ModuleData
->ModuleEnd
= ModuleData
->ModuleStart
+ ModuleSize
;
645 /* Set the next Module Base and increase the number of modules */
646 NextModuleBase
= ROUND_UP(ModuleData
->ModuleEnd
, PAGE_SIZE
);
647 LoaderBlock
.ModsCount
++;
649 /* Close the currently opened module */
650 CurrentModule
= NULL
;