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