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