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