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