Check if the cpu supports the pae mode.
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / 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 * Copyright (C) 2005 Hartmut Birr <hartmut.birr@gmx.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <freeldr.h>
23 #include <../arch/i386/hardware.h>
24 #include <internal/i386/ke.h>
25
26 #define NDEBUG
27 #include <debug.h>
28
29 /* Base Addres of Kernel in Physical Memory */
30 #define KERNEL_BASE_PHYS 0x200000
31
32 /* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
33 #define PFN_SHIFT 12
34
35 /* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
36 #define PDE_SHIFT 22
37 #define PDE_SHIFT_PAE 18
38
39
40 /* Converts a Relative Address read from the Kernel into a Physical Address */
41 #define RaToPa(p) \
42 (ULONG_PTR)((ULONG_PTR)p + KERNEL_BASE_PHYS)
43
44 /* Converts a Phsyical Address Pointer into a Page Frame Number */
45 #define PaPtrToPfn(p) \
46 (((ULONG_PTR)&p) >> PFN_SHIFT)
47
48 /* Converts a Phsyical Address into a Page Frame Number */
49 #define PaToPfn(p) \
50 ((p) >> PFN_SHIFT)
51
52 #define STARTUP_BASE 0xC0000000
53 #define HYPERSPACE_BASE 0xC0400000
54 #define HYPERSPACE_PAE_BASE 0xC0800000
55 #define APIC_BASE 0xFEC00000
56 #define KPCR_BASE 0xFF000000
57
58 #define LowMemPageTableIndex 0
59 #define StartupPageTableIndex (STARTUP_BASE >> 22)
60 #define HyperspacePageTableIndex (HYPERSPACE_BASE >> 22)
61 #define KpcrPageTableIndex (KPCR_BASE >> 22)
62 #define ApicPageTableIndex (APIC_BASE >> 22)
63
64 #define LowMemPageTableIndexPae 0
65 #define StartupPageTableIndexPae (STARTUP_BASE >> 21)
66 #define HyperspacePageTableIndexPae (HYPERSPACE_PAE_BASE >> 21)
67 #define KpcrPageTableIndexPae (KPCR_BASE >> 21)
68 #define ApicPageTableIndexPae (APIC_BASE >> 21)
69
70
71 #define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase
72
73 /* Load Address of Next Module */
74 ULONG_PTR NextModuleBase = 0;
75
76 /* Currently Opened Module */
77 PLOADER_MODULE CurrentModule = NULL;
78
79 /* Unrelocated Kernel Base in Virtual Memory */
80 ULONG_PTR KernelBase;
81
82 /* Wether PAE is to be used or not */
83 BOOLEAN PaeModeEnabled;
84
85 /* Kernel Entrypoint in Physical Memory */
86 ULONG_PTR KernelEntry;
87
88 typedef struct _HARDWARE_PTE_X64 {
89 ULONG Valid : 1;
90 ULONG Write : 1;
91 ULONG Owner : 1;
92 ULONG WriteThrough : 1;
93 ULONG CacheDisable : 1;
94 ULONG Accessed : 1;
95 ULONG Dirty : 1;
96 ULONG LargePage : 1;
97 ULONG Global : 1;
98 ULONG CopyOnWrite : 1;
99 ULONG Prototype : 1;
100 ULONG reserved : 1;
101 ULONG PageFrameNumber : 20;
102 ULONG reserved2 : 31;
103 ULONG NoExecute : 1;
104 } HARDWARE_PTE_X64, *PHARDWARE_PTE_X64;
105
106 typedef struct _PAGE_DIRECTORY_X86 {
107 HARDWARE_PTE_X86 Pde[1024];
108 } PAGE_DIRECTORY_X86, *PPAGE_DIRECTORY_X86;
109
110 typedef struct _PAGE_DIRECTORY_X64 {
111 HARDWARE_PTE_X64 Pde[2048];
112 } PAGE_DIRECTORY_X64, *PPAGE_DIRECTORY_X64;
113
114 typedef struct _PAGE_DIRECTORY_TABLE_X64 {
115 HARDWARE_PTE_X64 Pde[4];
116 } PAGE_DIRECTORY_TABLE_X64, *PPAGE_DIRECTORY_TABLE_X64;
117
118 /* Page Directory and Tables for non-PAE Systems */
119 extern PAGE_DIRECTORY_X86 startup_pagedirectory;
120 extern PAGE_DIRECTORY_X86 lowmem_pagetable;
121 extern PAGE_DIRECTORY_X86 kernel_pagetable;
122 extern ULONG_PTR hyperspace_pagetable;
123 extern ULONG_PTR _pae_pagedirtable;
124 extern PAGE_DIRECTORY_X86 apic_pagetable;
125 extern PAGE_DIRECTORY_X86 kpcr_pagetable;
126
127 /* Page Directory and Tables for PAE Systems */
128 extern PAGE_DIRECTORY_TABLE_X64 startup_pagedirectorytable_pae;
129 extern PAGE_DIRECTORY_X64 startup_pagedirectory_pae;
130 extern PAGE_DIRECTORY_X64 lowmem_pagetable_pae;
131 extern PAGE_DIRECTORY_X64 kernel_pagetable_pae;
132 extern ULONG_PTR hyperspace_pagetable_pae;
133 extern ULONG_PTR pagedirtable_pae;
134 extern PAGE_DIRECTORY_X64 apic_pagetable_pae;
135 extern PAGE_DIRECTORY_X64 kpcr_pagetable_pae;
136
137 /* FUNCTIONS *****************************************************************/
138
139 /*++
140 * FrLdrStartup
141 * INTERNAL
142 *
143 * Prepares the system for loading the Kernel.
144 *
145 * Params:
146 * Magic - Multiboot Magic
147 *
148 * Returns:
149 * None.
150 *
151 * Remarks:
152 * None.
153 *
154 *--*/
155 VOID
156 STDCALL
157 FrLdrStartup(ULONG Magic)
158 {
159 /* Disable Interrupts */
160 Ke386DisableInterrupts();
161
162 /* Re-initalize EFLAGS */
163 Ke386EraseFlags();
164
165 /* Get the PAE Mode */
166 FrLdrGetPaeMode();
167
168 /* Initialize the page directory */
169 FrLdrSetupPageDirectory();
170
171 /* Initialize Paging, Write-Protection and Load NTOSKRNL */
172 FrLdrSetupPae(Magic);
173 }
174
175 /*++
176 * FrLdrSetupPae
177 * INTERNAL
178 *
179 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
180 * the system is UP.
181 *
182 * Params:
183 * Magic - Multiboot Magic
184 *
185 * Returns:
186 * None.
187 *
188 * Remarks:
189 * None.
190 *
191 *--*/
192 VOID
193 FASTCALL
194 FrLdrSetupPae(ULONG Magic)
195 {
196 ULONG_PTR PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectory;
197 ASMCODE PagedJump;
198
199 if (PaeModeEnabled)
200 {
201 PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectorytable_pae;
202
203 /* Enable PAE */
204 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PAE);
205 }
206
207 /* Set the PDBR */
208 Ke386SetPageTableDirectory(PageDirectoryBaseAddress);
209
210 /* Enable Paging and Write Protect*/
211 Ke386SetCr0(Ke386GetCr0() | X86_CR0_PG | X86_CR0_WP);
212
213 /* Jump to Kernel */
214 PagedJump = (ASMCODE)(PVOID)(KernelEntryPoint);
215 PagedJump(Magic, &LoaderBlock);
216 }
217
218 /*++
219 * FrLdrGetKernelBase
220 * INTERNAL
221 *
222 * Gets the Kernel Base to use.
223 *
224 * Params:
225 *
226 * Returns:
227 * None.
228 *
229 * Remarks:
230 * Sets both the FreeLdr internal variable as well as the one which
231 * will be used by the Kernel.
232 *
233 *--*/
234 VOID
235 FASTCALL
236 FrLdrGetKernelBase(VOID)
237 {
238 PCHAR p;
239
240 /* Set KernelBase */
241 LoaderBlock.KernelBase = KernelBase;
242
243 /* Read Command Line */
244 p = (PCHAR)LoaderBlock.CommandLine;
245 while ((p = strchr(p, '/')) != NULL) {
246
247 /* Find "/3GB" */
248 if (!strnicmp(p + 1, "3GB", 3)) {
249
250 /* Make sure there's nothing following it */
251 if (p[4] == ' ' || p[4] == 0) {
252
253 /* Use 3GB */
254 KernelBase = 0xE0000000;
255 LoaderBlock.KernelBase = 0xC0000000;
256 }
257 }
258
259 p++;
260 }
261 }
262
263 /*++
264 * FrLdrGetPaeMode
265 * INTERNAL
266 *
267 * Determines whether PAE mode shoudl be enabled or not.
268 *
269 * Params:
270 * None.
271 *
272 * Returns:
273 * None.
274 *
275 * Remarks:
276 * None.
277 *
278 *--*/
279 VOID
280 FASTCALL
281 FrLdrGetPaeMode(VOID)
282 {
283 BOOLEAN PaeModeSupported;
284
285 PaeModeSupported = FALSE;
286 PaeModeEnabled = FALSE;
287
288 if (CpuidSupported() & 1)
289 {
290 ULONG eax, ebx, ecx, FeatureBits;
291 GetCpuid(1, &eax, &ebx, &ecx, &FeatureBits);
292 if (FeatureBits & X86_FEATURE_PAE)
293 {
294 PaeModeSupported = TRUE;
295 }
296 }
297
298 if (PaeModeSupported)
299 {
300 PCHAR p;
301
302 /* Read Command Line */
303 p = (PCHAR)LoaderBlock.CommandLine;
304 while ((p = strchr(p, '/')) != NULL) {
305
306 p++;
307 /* Find "PAE" */
308 if (!strnicmp(p, "PAE", 3)) {
309
310 /* Make sure there's nothing following it */
311 if (p[3] == ' ' || p[3] == 0) {
312
313 /* Use Pae */
314 PaeModeEnabled = TRUE;
315 break;
316 }
317 }
318 }
319 }
320 }
321
322 /*++
323 * FrLdrSetupPageDirectory
324 * INTERNAL
325 *
326 * Sets up the ReactOS Startup Page Directory.
327 *
328 * Params:
329 * None.
330 *
331 * Returns:
332 * None.
333 *
334 * Remarks:
335 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
336 * As such, please note that PageFrameNumber == PageEntryNumber.
337 *
338 *--*/
339 VOID
340 FASTCALL
341 FrLdrSetupPageDirectory(VOID)
342 {
343 PPAGE_DIRECTORY_X86 PageDir;
344 PPAGE_DIRECTORY_TABLE_X64 PageDirTablePae;
345 PPAGE_DIRECTORY_X64 PageDirPae;
346 ULONG KernelPageTableIndex;
347 ULONG i;
348
349 if (PaeModeEnabled) {
350
351 /* Get the Kernel Table Index */
352 KernelPageTableIndex = (KernelBase >> 21);
353
354 /* Get the Startup Page Directory Table */
355 PageDirTablePae = (PPAGE_DIRECTORY_TABLE_X64)&startup_pagedirectorytable_pae;
356
357 /* Get the Startup Page Directory */
358 PageDirPae = (PPAGE_DIRECTORY_X64)&startup_pagedirectory_pae;
359
360 /* Set the Startup page directory table */
361 for (i = 0; i < 4; i++)
362 {
363 PageDirTablePae->Pde[i].Valid = 1;
364 PageDirTablePae->Pde[i].PageFrameNumber = PaPtrToPfn(startup_pagedirectory_pae) + i;
365 }
366
367 /* Set up the Low Memory PDE */
368 for (i = 0; i < 2; i++)
369 {
370 PageDirPae->Pde[LowMemPageTableIndexPae + i].Valid = 1;
371 PageDirPae->Pde[LowMemPageTableIndexPae + i].Write = 1;
372 PageDirPae->Pde[LowMemPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(lowmem_pagetable_pae) + i;
373 }
374
375 /* Set up the Kernel PDEs */
376 for (i = 0; i < 3; i++)
377 {
378 PageDirPae->Pde[KernelPageTableIndex + i].Valid = 1;
379 PageDirPae->Pde[KernelPageTableIndex + i].Write = 1;
380 PageDirPae->Pde[KernelPageTableIndex + i].PageFrameNumber = PaPtrToPfn(kernel_pagetable_pae) + i;
381 }
382
383 /* Set up the Startup PDE */
384 for (i = 0; i < 4; i++)
385 {
386 PageDirPae->Pde[StartupPageTableIndexPae + i].Valid = 1;
387 PageDirPae->Pde[StartupPageTableIndexPae + i].Write = 1;
388 PageDirPae->Pde[StartupPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(startup_pagedirectory_pae) + i;
389 }
390
391 /* Set up the Hyperspace PDE */
392 for (i = 0; i < 2; i++)
393 {
394 PageDirPae->Pde[HyperspacePageTableIndexPae + i].Valid = 1;
395 PageDirPae->Pde[HyperspacePageTableIndexPae + i].Write = 1;
396 PageDirPae->Pde[HyperspacePageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable_pae) + i;
397 }
398
399 /* Set up the Apic PDE */
400 for (i = 0; i < 2; i++)
401 {
402 PageDirPae->Pde[ApicPageTableIndexPae + i].Valid = 1;
403 PageDirPae->Pde[ApicPageTableIndexPae + i].Write = 1;
404 PageDirPae->Pde[ApicPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(apic_pagetable_pae) + i;
405 }
406
407 /* Set up the KPCR PDE */
408 PageDirPae->Pde[KpcrPageTableIndexPae].Valid = 1;
409 PageDirPae->Pde[KpcrPageTableIndexPae].Write = 1;
410 PageDirPae->Pde[KpcrPageTableIndexPae].PageFrameNumber = PaPtrToPfn(kpcr_pagetable_pae);
411
412 /* Set up Low Memory PTEs */
413 PageDirPae = (PPAGE_DIRECTORY_X64)&lowmem_pagetable_pae;
414 for (i=0; i<1024; i++) {
415
416 PageDirPae->Pde[i].Valid = 1;
417 PageDirPae->Pde[i].Write = 1;
418 PageDirPae->Pde[i].Owner = 1;
419 PageDirPae->Pde[i].PageFrameNumber = i;
420 }
421
422 /* Set up Kernel PTEs */
423 PageDirPae = (PPAGE_DIRECTORY_X64)&kernel_pagetable_pae;
424 for (i=0; i<1536; i++) {
425
426 PageDirPae->Pde[i].Valid = 1;
427 PageDirPae->Pde[i].Write = 1;
428 PageDirPae->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS) + i;
429 }
430
431 /* Set up APIC PTEs */
432 PageDirPae = (PPAGE_DIRECTORY_X64)&apic_pagetable_pae;
433 PageDirPae->Pde[0].Valid = 1;
434 PageDirPae->Pde[0].Write = 1;
435 PageDirPae->Pde[0].CacheDisable = 1;
436 PageDirPae->Pde[0].WriteThrough = 1;
437 PageDirPae->Pde[0].PageFrameNumber = PaToPfn(APIC_BASE);
438 PageDirPae->Pde[0x200].Valid = 1;
439 PageDirPae->Pde[0x200].Write = 1;
440 PageDirPae->Pde[0x200].CacheDisable = 1;
441 PageDirPae->Pde[0x200].WriteThrough = 1;
442 PageDirPae->Pde[0x200].PageFrameNumber = PaToPfn(APIC_BASE + KERNEL_BASE_PHYS);
443
444 /* Set up KPCR PTEs */
445 PageDirPae = (PPAGE_DIRECTORY_X64)&kpcr_pagetable_pae;
446 PageDirPae->Pde[0].Valid = 1;
447 PageDirPae->Pde[0].Write = 1;
448 PageDirPae->Pde[0].PageFrameNumber = 1;
449
450 } else {
451
452 /* Get the Kernel Table Index */
453 KernelPageTableIndex = KernelBase >> PDE_SHIFT;
454
455 /* Get the Startup Page Directory */
456 PageDir = (PPAGE_DIRECTORY_X86)&startup_pagedirectory;
457
458 /* Set up the Low Memory PDE */
459 PageDir->Pde[LowMemPageTableIndex].Valid = 1;
460 PageDir->Pde[LowMemPageTableIndex].Write = 1;
461 PageDir->Pde[LowMemPageTableIndex].PageFrameNumber = PaPtrToPfn(lowmem_pagetable);
462
463 /* Set up the Kernel PDEs */
464 PageDir->Pde[KernelPageTableIndex].Valid = 1;
465 PageDir->Pde[KernelPageTableIndex].Write = 1;
466 PageDir->Pde[KernelPageTableIndex].PageFrameNumber = PaPtrToPfn(kernel_pagetable);
467 PageDir->Pde[KernelPageTableIndex + 1].Valid = 1;
468 PageDir->Pde[KernelPageTableIndex + 1].Write = 1;
469 PageDir->Pde[KernelPageTableIndex + 1].PageFrameNumber = PaPtrToPfn(kernel_pagetable + 4096);
470
471 /* Set up the Startup PDE */
472 PageDir->Pde[StartupPageTableIndex].Valid = 1;
473 PageDir->Pde[StartupPageTableIndex].Write = 1;
474 PageDir->Pde[StartupPageTableIndex].PageFrameNumber = PaPtrToPfn(startup_pagedirectory);
475
476 /* Set up the Hyperspace PDE */
477 PageDir->Pde[HyperspacePageTableIndex].Valid = 1;
478 PageDir->Pde[HyperspacePageTableIndex].Write = 1;
479 PageDir->Pde[HyperspacePageTableIndex].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable);
480
481 /* Set up the Apic PDE */
482 PageDir->Pde[ApicPageTableIndex].Valid = 1;
483 PageDir->Pde[ApicPageTableIndex].Write = 1;
484 PageDir->Pde[ApicPageTableIndex].PageFrameNumber = PaPtrToPfn(apic_pagetable);
485
486 /* Set up the KPCR PDE */
487 PageDir->Pde[KpcrPageTableIndex].Valid = 1;
488 PageDir->Pde[KpcrPageTableIndex].Write = 1;
489 PageDir->Pde[KpcrPageTableIndex].PageFrameNumber = PaPtrToPfn(kpcr_pagetable);
490
491 /* Set up Low Memory PTEs */
492 PageDir = (PPAGE_DIRECTORY_X86)&lowmem_pagetable;
493 for (i=0; i<1024; i++) {
494
495 PageDir->Pde[i].Valid = 1;
496 PageDir->Pde[i].Write = 1;
497 PageDir->Pde[i].Owner = 1;
498 PageDir->Pde[i].PageFrameNumber = PaToPfn(i * PAGE_SIZE);
499 }
500
501 /* Set up Kernel PTEs */
502 PageDir = (PPAGE_DIRECTORY_X86)&kernel_pagetable;
503 for (i=0; i<1536; i++) {
504
505 PageDir->Pde[i].Valid = 1;
506 PageDir->Pde[i].Write = 1;
507 PageDir->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS + i * PAGE_SIZE);
508 }
509
510 /* Set up APIC PTEs */
511 PageDir = (PPAGE_DIRECTORY_X86)&apic_pagetable;
512 PageDir->Pde[0].Valid = 1;
513 PageDir->Pde[0].Write = 1;
514 PageDir->Pde[0].CacheDisable = 1;
515 PageDir->Pde[0].WriteThrough = 1;
516 PageDir->Pde[0].PageFrameNumber = PaToPfn(APIC_BASE);
517 PageDir->Pde[0x200].Valid = 1;
518 PageDir->Pde[0x200].Write = 1;
519 PageDir->Pde[0x200].CacheDisable = 1;
520 PageDir->Pde[0x200].WriteThrough = 1;
521 PageDir->Pde[0x200].PageFrameNumber = PaToPfn(APIC_BASE + KERNEL_BASE_PHYS);
522
523 /* Set up KPCR PTEs */
524 PageDir = (PPAGE_DIRECTORY_X86)&kpcr_pagetable;
525 PageDir->Pde[0].Valid = 1;
526 PageDir->Pde[0].Write = 1;
527 PageDir->Pde[0].PageFrameNumber = 1;
528 }
529 return;
530 }
531
532 /*++
533 * FrLdrMapKernel
534 * INTERNAL
535 *
536 * Maps the Kernel into memory, does PE Section Mapping, initalizes the
537 * uninitialized data sections, and relocates the image.
538 *
539 * Params:
540 * KernelImage - FILE Structure representing the ntoskrnl image file.
541 *
542 * Returns:
543 * TRUE if the Kernel was mapped.
544 *
545 * Remarks:
546 * None.
547 *
548 *--*/
549 BOOL
550 STDCALL
551 FrLdrMapKernel(FILE *KernelImage)
552 {
553 PIMAGE_DOS_HEADER ImageHeader;
554 PIMAGE_NT_HEADERS NtHeader;
555 PIMAGE_SECTION_HEADER Section;
556 ULONG SectionCount;
557 ULONG ImageSize;
558 ULONG_PTR SourceSection;
559 ULONG_PTR TargetSection;
560 ULONG SectionSize;
561 INT i;
562 PIMAGE_DATA_DIRECTORY RelocationDDir;
563 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
564 ULONG Count;
565 ULONG_PTR Address, MaxAddress;
566 PUSHORT TypeOffset;
567 ULONG_PTR Delta;
568 PUSHORT ShortPtr;
569 PULONG LongPtr;
570
571 /* Allocate 1024 bytes for PE Header */
572 ImageHeader = (PIMAGE_DOS_HEADER)MmAllocateMemory(1024);
573
574 /* Make sure it was succesful */
575 if (ImageHeader == NULL) {
576
577 return FALSE;
578 }
579
580 /* Load the first 1024 bytes of the kernel image so we can read the PE header */
581 if (!FsReadFile(KernelImage, 1024, NULL, ImageHeader)) {
582
583 /* Fail if we couldn't read */
584 MmFreeMemory(ImageHeader);
585 return FALSE;
586 }
587
588 /* Now read the MZ header to get the offset to the PE Header */
589 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)ImageHeader + ImageHeader->e_lfanew);
590
591 /* Get Kernel Base */
592 KernelBase = NtHeader->OptionalHeader.ImageBase;
593 FrLdrGetKernelBase();
594
595 /* Save Entrypoint */
596 KernelEntry = RaToPa(NtHeader->OptionalHeader.AddressOfEntryPoint);
597
598 /* Save the Image Size */
599 ImageSize = NtHeader->OptionalHeader.SizeOfImage;
600
601 /* Free the Header */
602 MmFreeMemory(ImageHeader);
603
604 /* Set the file pointer to zero */
605 FsSetFilePointer(KernelImage, 0);
606
607 /* Load the file image */
608 FsReadFile(KernelImage, ImageSize, NULL, (PVOID)KERNEL_BASE_PHYS);
609
610 /* Reload the NT Header */
611 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)KERNEL_BASE_PHYS + ImageHeader->e_lfanew);
612
613 /* Load the first section */
614 Section = IMAGE_FIRST_SECTION(NtHeader);
615 SectionCount = NtHeader->FileHeader.NumberOfSections - 1;
616
617 /* Now go to the last section */
618 Section += SectionCount;
619
620 /* Walk each section backwards */
621 for (i=(INT)SectionCount; i >= 0; i--, Section--) {
622
623 /* Get the disk location and the memory location, and the size */
624 SourceSection = RaToPa(Section->PointerToRawData);
625 TargetSection = RaToPa(Section->VirtualAddress);
626 SectionSize = Section->SizeOfRawData;
627
628 /* If the section is already mapped correctly, go to the next */
629 if (SourceSection == TargetSection) continue;
630
631 /* Load it into memory */
632 memmove((PVOID)TargetSection, (PVOID)SourceSection, SectionSize);
633
634 /* Check for unitilizated data */
635 if (Section->SizeOfRawData < Section->Misc.VirtualSize) {
636
637 /* Zero it out */
638 memset((PVOID)RaToPa(Section->VirtualAddress + Section->SizeOfRawData),
639 0,
640 Section->Misc.VirtualSize - Section->SizeOfRawData);
641 }
642 }
643
644 /* Get the Relocation Data Directory */
645 RelocationDDir = &NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
646
647 /* Get the Relocation Section Start and End*/
648 RelocationDir = (PIMAGE_BASE_RELOCATION)(KERNEL_BASE_PHYS + RelocationDDir->VirtualAddress);
649 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
650
651 /* Calculate Difference between Real Base and Compiled Base*/
652 Delta = KernelBase - NtHeader->OptionalHeader.ImageBase;
653
654 /* Determine how far we shoudl relocate */
655 MaxAddress = KERNEL_BASE_PHYS + ImageSize;
656
657 /* Relocate until we've processed all the blocks */
658 while (RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0) {
659
660 /* See how many Relocation Blocks we have */
661 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
662
663 /* Calculate the Address of this Directory */
664 Address = KERNEL_BASE_PHYS + RelocationDir->VirtualAddress;
665
666 /* Calculate the Offset of the Type */
667 TypeOffset = (PUSHORT)(RelocationDir + 1);
668
669 for (i = 0; i < (INT)Count; i++) {
670
671 ShortPtr = (PUSHORT)(Address + (*TypeOffset & 0xFFF));
672
673 switch (*TypeOffset >> 12) {
674
675 case IMAGE_REL_BASED_ABSOLUTE:
676 break;
677
678 case IMAGE_REL_BASED_HIGH:
679 *ShortPtr += HIWORD(Delta);
680 break;
681
682 case IMAGE_REL_BASED_LOW:
683 *ShortPtr += LOWORD(Delta);
684 break;
685
686 case IMAGE_REL_BASED_HIGHLOW:
687 LongPtr = (PULONG)ShortPtr;
688 *LongPtr += Delta;
689 break;
690 }
691
692 TypeOffset++;
693 }
694
695 /* Move to the next Relocation Table */
696 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
697 }
698
699 /* Increase the next Load Base */
700 NextModuleBase = ROUND_UP(KERNEL_BASE_PHYS + ImageSize, PAGE_SIZE);
701
702 /* Return Success */
703 return TRUE;
704 }
705
706 ULONG_PTR
707 STDCALL
708 FrLdrLoadModule(FILE *ModuleImage,
709 LPSTR ModuleName,
710 PULONG ModuleSize)
711 {
712 ULONG LocalModuleSize;
713 PLOADER_MODULE ModuleData;
714 LPSTR NameBuffer;
715 LPSTR TempName;
716
717 /* Get current module data structure and module name string array */
718 ModuleData = &reactos_modules[LoaderBlock.ModsCount];
719
720 /* Get only the Module Name */
721 do {
722
723 TempName = strchr(ModuleName, '\\');
724
725 if(TempName) {
726 ModuleName = TempName + 1;
727 }
728
729 } while(TempName);
730 NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
731
732 /* Get Module Size */
733 LocalModuleSize = FsGetFileSize(ModuleImage);
734
735 /* Fill out Module Data Structure */
736 ModuleData->ModStart = NextModuleBase;
737 ModuleData->ModEnd = NextModuleBase + LocalModuleSize;
738
739 /* Save name */
740 strcpy(NameBuffer, ModuleName);
741 ModuleData->String = (ULONG_PTR)NameBuffer;
742
743 /* Load the file image */
744 FsReadFile(ModuleImage, LocalModuleSize, NULL, (PVOID)NextModuleBase);
745
746 /* Move to next memory block and increase Module Count */
747 NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
748 LoaderBlock.ModsCount++;
749
750 /* Return Module Size if required */
751 if (ModuleSize != NULL) {
752 *ModuleSize = LocalModuleSize;
753 }
754
755 return(ModuleData->ModStart);
756 }
757
758 ULONG_PTR
759 STDCALL
760 FrLdrCreateModule(LPSTR ModuleName)
761 {
762 PLOADER_MODULE ModuleData;
763 LPSTR NameBuffer;
764
765 /* Get current module data structure and module name string array */
766 ModuleData = &reactos_modules[LoaderBlock.ModsCount];
767 NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
768
769 /* Set up the structure */
770 ModuleData->ModStart = NextModuleBase;
771 ModuleData->ModEnd = -1;
772
773 /* Copy the name */
774 strcpy(NameBuffer, ModuleName);
775 ModuleData->String = (ULONG_PTR)NameBuffer;
776
777 /* Set the current Module */
778 CurrentModule = ModuleData;
779
780 /* Return Module Base Address */
781 return(ModuleData->ModStart);
782 }
783
784 BOOL
785 STDCALL
786 FrLdrCloseModule(ULONG_PTR ModuleBase,
787 ULONG ModuleSize)
788 {
789 PLOADER_MODULE ModuleData = CurrentModule;
790
791 /* Make sure a module is opened */
792 if (ModuleData) {
793
794 /* Make sure this is the right module and that it hasn't been closed */
795 if ((ModuleBase == ModuleData->ModStart) && (ModuleData->ModEnd == (ULONG_PTR)-1)) {
796
797 /* Close the Module */
798 ModuleData->ModEnd = ModuleData->ModStart + ModuleSize;
799
800 /* Set the next Module Base and increase the number of modules */
801 NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
802 LoaderBlock.ModsCount++;
803
804 /* Close the currently opened module */
805 CurrentModule = NULL;
806
807 /* Success */
808 return(TRUE);
809 }
810 }
811
812 /* Failure path */
813 return(FALSE);
814 }