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.
28 static PVOID KernelMemory
= 0;
30 /* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
33 /* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
35 #define PDE_SHIFT_PAE 18
38 /* Converts a Relative Address read from the Kernel into a Physical Address */
39 ULONG
RaToPa(ULONG p
) {
40 return ofw_virt2phys((ULONG
)(p
+ KernelMemory
), 1);
43 /* Converts a Phsyical Address Pointer into a Page Frame Number */
44 #define PaPtrToPfn(p) \
45 (((ULONG_PTR)&p) >> PFN_SHIFT)
47 /* Converts a Phsyical Address into a Page Frame Number */
51 #define STARTUP_BASE 0xC0000000
52 #define HYPERSPACE_BASE 0xC0400000
53 #define HYPERSPACE_PAE_BASE 0xC0800000
54 #define APIC_BASE 0xFEC00000
55 #define KPCR_BASE 0xFF000000
57 #define LowMemPageTableIndex 0
58 #define StartupPageTableIndex (STARTUP_BASE >> 22)
59 #define HyperspacePageTableIndex (HYPERSPACE_BASE >> 22)
60 #define KpcrPageTableIndex (KPCR_BASE >> 22)
61 #define ApicPageTableIndex (APIC_BASE >> 22)
63 #define LowMemPageTableIndexPae 0
64 #define StartupPageTableIndexPae (STARTUP_BASE >> 21)
65 #define HyperspacePageTableIndexPae (HYPERSPACE_PAE_BASE >> 21)
66 #define KpcrPageTableIndexPae (KPCR_BASE >> 21)
67 #define ApicPageTableIndexPae (APIC_BASE >> 21)
70 #define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase
72 /* Load Address of Next Module */
73 ULONG_PTR NextModuleBase
= 0;
75 /* Currently Opened Module */
76 PLOADER_MODULE CurrentModule
= NULL
;
78 /* Unrelocated Kernel Base in Virtual Memory */
81 /* Wether PAE is to be used or not */
82 BOOLEAN PaeModeEnabled
;
84 /* Kernel Entrypoint in Physical Memory */
85 ULONG_PTR KernelEntry
;
87 /* FUNCTIONS *****************************************************************/
93 * Prepares the system for loading the Kernel.
96 * Magic - Multiboot Magic
107 FrLdrStartup(ULONG Magic
)
115 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
119 * Magic - Multiboot Magic
130 FrLdrSetupPae(ULONG Magic
)
138 * Gets the Kernel Base to use.
146 * Sets both the FreeLdr internal variable as well as the one which
147 * will be used by the Kernel.
152 FrLdrGetKernelBase(VOID
)
157 LoaderBlock
.KernelBase
= KernelBase
;
159 /* Read Command Line */
160 p
= (PCHAR
)LoaderBlock
.CommandLine
;
161 while ((p
= strchr(p
, '/')) != NULL
) {
164 if (!_strnicmp(p
+ 1, "3GB", 3)) {
166 /* Make sure there's nothing following it */
167 if (p
[4] == ' ' || p
[4] == 0) {
170 KernelBase
= 0xE0000000;
171 LoaderBlock
.KernelBase
= 0xC0000000;
183 * Determines whether PAE mode shoudl be enabled or not.
197 FrLdrGetPaeMode(VOID
)
202 * FrLdrSetupPageDirectory
205 * Sets up the ReactOS Startup Page Directory.
214 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
215 * As such, please note that PageFrameNumber == PageEntryNumber.
220 FrLdrSetupPageDirectory(VOID
)
228 * Maps the Kernel into memory, does PE Section Mapping, initalizes the
229 * uninitialized data sections, and relocates the image.
232 * KernelImage - FILE Structure representing the ntoskrnl image file.
235 * TRUE if the Kernel was mapped.
243 FrLdrMapKernel(FILE *KernelImage
)
245 PIMAGE_DOS_HEADER ImageHeader
;
246 PIMAGE_NT_HEADERS NtHeader
;
247 PIMAGE_SECTION_HEADER Section
;
250 ULONG_PTR SourceSection
;
251 ULONG_PTR TargetSection
;
254 PIMAGE_DATA_DIRECTORY RelocationDDir
;
255 PIMAGE_BASE_RELOCATION RelocationDir
, RelocationEnd
;
257 ULONG_PTR Address
, MaxAddress
;
263 /* Allocate 1024 bytes for PE Header */
264 ImageHeader
= (PIMAGE_DOS_HEADER
)MmAllocateMemory(1024);
266 /* Make sure it was succesful */
267 if (ImageHeader
== NULL
) {
272 /* Load the first 1024 bytes of the kernel image so we can read the PE header */
273 if (!FsReadFile(KernelImage
, 1024, NULL
, ImageHeader
)) {
275 /* Fail if we couldn't read */
276 MmFreeMemory(ImageHeader
);
280 /* Now read the MZ header to get the offset to the PE Header */
281 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)ImageHeader
+ ImageHeader
->e_lfanew
);
283 /* Get Kernel Base */
284 KernelBase
= NtHeader
->OptionalHeader
.ImageBase
;
285 FrLdrGetKernelBase();
287 printf("About to do RaToPa(%x)\n",
288 NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
289 /* Save Entrypoint */
290 KernelEntry
= RaToPa(NtHeader
->OptionalHeader
.AddressOfEntryPoint
);
291 printf("RaToPa -> %x\n", KernelEntry
);
293 /* Save the Image Size */
294 ImageSize
= NtHeader
->OptionalHeader
.SizeOfImage
;
296 /* Free the Header */
297 MmFreeMemory(ImageHeader
);
299 /* Set the file pointer to zero */
300 FsSetFilePointer(KernelImage
, 0);
302 /* Allocate kernel memory */
303 KernelMemory
= MmAllocateMemory(ImageSize
);
305 /* Load the file image */
306 FsReadFile(KernelImage
, ImageSize
, NULL
, KernelMemory
);
308 /* Reload the NT Header */
309 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)KernelMemory
+ ImageHeader
->e_lfanew
);
311 /* Load the first section */
312 Section
= IMAGE_FIRST_SECTION(NtHeader
);
313 SectionCount
= NtHeader
->FileHeader
.NumberOfSections
- 1;
315 /* Now go to the last section */
316 Section
+= SectionCount
;
318 /* Walk each section backwards */
319 for (i
=(INT
)SectionCount
; i
>= 0; i
--, Section
--) {
321 /* Get the disk location and the memory location, and the size */
322 SourceSection
= RaToPa(Section
->PointerToRawData
);
323 TargetSection
= RaToPa(Section
->VirtualAddress
);
324 SectionSize
= Section
->SizeOfRawData
;
326 /* If the section is already mapped correctly, go to the next */
327 if (SourceSection
== TargetSection
) continue;
329 /* Load it into memory */
330 memmove((PVOID
)TargetSection
, (PVOID
)SourceSection
, SectionSize
);
332 /* Check for unitilizated data */
333 if (Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
336 memset((PVOID
)RaToPa(Section
->VirtualAddress
+ Section
->SizeOfRawData
),
338 Section
->Misc
.VirtualSize
- Section
->SizeOfRawData
);
342 /* Get the Relocation Data Directory */
343 RelocationDDir
= &NtHeader
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
345 /* Get the Relocation Section Start and End*/
346 RelocationDir
= (PIMAGE_BASE_RELOCATION
)(KernelMemory
+ RelocationDDir
->VirtualAddress
);
347 RelocationEnd
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)RelocationDir
+ RelocationDDir
->Size
);
349 /* Calculate Difference between Real Base and Compiled Base*/
350 Delta
= KernelBase
- NtHeader
->OptionalHeader
.ImageBase
;
352 /* Determine how far we shoudl relocate */
353 MaxAddress
= (ULONG
)KernelMemory
+ ImageSize
;
355 /* Relocate until we've processed all the blocks */
356 while (RelocationDir
< RelocationEnd
&& RelocationDir
->SizeOfBlock
> 0) {
358 /* See how many Relocation Blocks we have */
359 Count
= (RelocationDir
->SizeOfBlock
- sizeof(IMAGE_BASE_RELOCATION
)) / sizeof(USHORT
);
361 /* Calculate the Address of this Directory */
362 Address
= (ULONG
)KernelMemory
+ RelocationDir
->VirtualAddress
;
364 /* Calculate the Offset of the Type */
365 TypeOffset
= (PUSHORT
)(RelocationDir
+ 1);
367 for (i
= 0; i
< (INT
)Count
; i
++) {
369 ShortPtr
= (PUSHORT
)(Address
+ (*TypeOffset
& 0xFFF));
371 switch (*TypeOffset
>> 12) {
373 case IMAGE_REL_BASED_ABSOLUTE
:
376 case IMAGE_REL_BASED_HIGH
:
377 *ShortPtr
+= HIWORD(Delta
);
380 case IMAGE_REL_BASED_LOW
:
381 *ShortPtr
+= LOWORD(Delta
);
384 case IMAGE_REL_BASED_HIGHLOW
:
385 LongPtr
= (PULONG
)ShortPtr
;
393 /* Move to the next Relocation Table */
394 RelocationDir
= (PIMAGE_BASE_RELOCATION
)((ULONG_PTR
)RelocationDir
+ RelocationDir
->SizeOfBlock
);
397 /* Increase the next Load Base */
398 NextModuleBase
= ROUND_UP((ULONG
)KernelMemory
+ ImageSize
, PAGE_SIZE
);
406 FrLdrLoadModule(FILE *ModuleImage
,
410 ULONG LocalModuleSize
;
411 PLOADER_MODULE ModuleData
;
415 /* Get current module data structure and module name string array */
416 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
418 /* Get only the Module Name */
421 TempName
= strchr(ModuleName
, '\\');
424 ModuleName
= TempName
+ 1;
428 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
430 /* Get Module Size */
431 LocalModuleSize
= FsGetFileSize(ModuleImage
);
433 /* Fill out Module Data Structure */
434 ModuleData
->ModStart
= NextModuleBase
;
435 ModuleData
->ModEnd
= NextModuleBase
+ LocalModuleSize
;
438 strcpy(NameBuffer
, ModuleName
);
439 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
441 /* Load the file image */
442 FsReadFile(ModuleImage
, LocalModuleSize
, NULL
, (PVOID
)NextModuleBase
);
444 /* Move to next memory block and increase Module Count */
445 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
446 LoaderBlock
.ModsCount
++;
448 /* Return Module Size if required */
449 if (ModuleSize
!= NULL
) {
450 *ModuleSize
= LocalModuleSize
;
453 return(ModuleData
->ModStart
);
458 FrLdrCreateModule(LPCSTR ModuleName
)
460 PLOADER_MODULE ModuleData
;
463 /* Get current module data structure and module name string array */
464 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
465 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
467 /* Set up the structure */
468 ModuleData
->ModStart
= NextModuleBase
;
469 ModuleData
->ModEnd
= -1;
472 strcpy(NameBuffer
, ModuleName
);
473 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
475 /* Set the current Module */
476 CurrentModule
= ModuleData
;
478 /* Return Module Base Address */
479 return(ModuleData
->ModStart
);
484 FrLdrCloseModule(ULONG_PTR ModuleBase
,
487 PLOADER_MODULE ModuleData
= CurrentModule
;
489 /* Make sure a module is opened */
492 /* Make sure this is the right module and that it hasn't been closed */
493 if ((ModuleBase
== ModuleData
->ModStart
) && (ModuleData
->ModEnd
== (ULONG_PTR
)-1)) {
495 /* Close the Module */
496 ModuleData
->ModEnd
= ModuleData
->ModStart
+ ModuleSize
;
498 /* Set the next Module Base and increase the number of modules */
499 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
500 LoaderBlock
.ModsCount
++;
502 /* Close the currently opened module */
503 CurrentModule
= NULL
;