3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
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.
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.
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.
27 /* Load Address of Next Module */
28 ULONG_PTR NextModuleBase
= KERNEL_BASE_PHYS
;
30 /* Currently Opened Module */
31 PLOADER_MODULE CurrentModule
= NULL
;
33 /* Unrelocated Kernel Base in Virtual Memory */
36 /* Kernel Entrypoint in Virtual Memory */
37 ULONG_PTR KernelEntryPoint
;
39 /* Page Directory and Tables for non-PAE Systems */
40 extern PAGE_DIRECTORY_X86 startup_pagedirectory
;
41 extern PAGE_DIRECTORY_X86 lowmem_pagetable
;
42 extern PAGE_DIRECTORY_X86 kernel_pagetable
;
43 extern PAGE_DIRECTORY_X86 hyperspace_pagetable
;
44 extern PAGE_DIRECTORY_X86 apic_pagetable
;
45 extern PAGE_DIRECTORY_X86 kpcr_pagetable
;
46 extern PAGE_DIRECTORY_X86 kuser_pagetable
;
50 LdrPEGetExportByName(PVOID BaseAddress
,
54 /* FUNCTIONS *****************************************************************/
60 * Prepares the system for loading the Kernel.
63 * Magic - Multiboot Magic
74 FrLdrStartup(ULONG Magic
)
76 /* Disable Interrupts */
79 /* Re-initalize EFLAGS */
82 /* Initialize the page directory */
83 FrLdrSetupPageDirectory();
85 /* Initialize Paging, Write-Protection and Load NTOSKRNL */
93 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
97 * Magic - Multiboot Magic
108 FrLdrSetupPae(ULONG Magic
)
110 ULONG_PTR PageDirectoryBaseAddress
= (ULONG_PTR
)&startup_pagedirectory
;
114 __writecr3(PageDirectoryBaseAddress
);
116 /* Enable Paging and Write Protect*/
117 __writecr0(__readcr0() | X86_CR0_PG
| X86_CR0_WP
);
120 PagedJump
= (ASMCODE
)(PVOID
)(KernelEntryPoint
);
121 PagedJump(Magic
, &LoaderBlock
);
125 * FrLdrSetupPageDirectory
128 * Sets up the ReactOS Startup Page Directory.
137 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
138 * As such, please note that PageFrameNumber == PageEntryNumber.
143 FrLdrSetupPageDirectory(VOID
)
145 PPAGE_DIRECTORY_X86 PageDir
;
146 ULONG KernelPageTableIndex
;
149 /* Get the Kernel Table Index */
150 KernelPageTableIndex
= KernelBase
>> PDE_SHIFT
;
152 /* Get the Startup Page Directory */
153 PageDir
= (PPAGE_DIRECTORY_X86
)&startup_pagedirectory
;
155 /* Set up the Low Memory PDE */
156 PageDir
->Pde
[LowMemPageTableIndex
].Valid
= 1;
157 PageDir
->Pde
[LowMemPageTableIndex
].Write
= 1;
158 PageDir
->Pde
[LowMemPageTableIndex
].PageFrameNumber
= PaPtrToPfn(lowmem_pagetable
);
160 /* Set up the Kernel PDEs */
161 PageDir
->Pde
[KernelPageTableIndex
].Valid
= 1;
162 PageDir
->Pde
[KernelPageTableIndex
].Write
= 1;
163 PageDir
->Pde
[KernelPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
);
164 PageDir
->Pde
[KernelPageTableIndex
+ 1].Valid
= 1;
165 PageDir
->Pde
[KernelPageTableIndex
+ 1].Write
= 1;
166 PageDir
->Pde
[KernelPageTableIndex
+ 1].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
+ 4096);
168 /* Set up the Startup PDE */
169 PageDir
->Pde
[StartupPageTableIndex
].Valid
= 1;
170 PageDir
->Pde
[StartupPageTableIndex
].Write
= 1;
171 PageDir
->Pde
[StartupPageTableIndex
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory
);
173 /* Set up the Hyperspace PDE */
174 PageDir
->Pde
[HyperspacePageTableIndex
].Valid
= 1;
175 PageDir
->Pde
[HyperspacePageTableIndex
].Write
= 1;
176 PageDir
->Pde
[HyperspacePageTableIndex
].PageFrameNumber
= PaPtrToPfn(hyperspace_pagetable
);
178 /* Set up the HAL PDE */
179 PageDir
->Pde
[HalPageTableIndex
].Valid
= 1;
180 PageDir
->Pde
[HalPageTableIndex
].Write
= 1;
181 PageDir
->Pde
[HalPageTableIndex
].PageFrameNumber
= PaPtrToPfn(apic_pagetable
);
183 /* Set up Low Memory PTEs */
184 PageDir
= (PPAGE_DIRECTORY_X86
)&lowmem_pagetable
;
185 for (i
=0; i
<1024; i
++)
187 PageDir
->Pde
[i
].Valid
= 1;
188 PageDir
->Pde
[i
].Write
= 1;
189 PageDir
->Pde
[i
].Owner
= 1;
190 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(i
* PAGE_SIZE
);
193 /* Set up Kernel PTEs */
194 PageDir
= (PPAGE_DIRECTORY_X86
)&kernel_pagetable
;
195 for (i
=0; i
<1536; i
++)
197 PageDir
->Pde
[i
].Valid
= 1;
198 PageDir
->Pde
[i
].Write
= 1;
199 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
+ i
* PAGE_SIZE
);
202 /* Setup APIC Base */
203 PageDir
= (PPAGE_DIRECTORY_X86
)&apic_pagetable
;
204 PageDir
->Pde
[0].Valid
= 1;
205 PageDir
->Pde
[0].Write
= 1;
206 PageDir
->Pde
[0].CacheDisable
= 1;
207 PageDir
->Pde
[0].WriteThrough
= 1;
208 PageDir
->Pde
[0].PageFrameNumber
= PaToPfn(HAL_BASE
);
209 PageDir
->Pde
[0x200].Valid
= 1;
210 PageDir
->Pde
[0x200].Write
= 1;
211 PageDir
->Pde
[0x200].CacheDisable
= 1;
212 PageDir
->Pde
[0x200].WriteThrough
= 1;
213 PageDir
->Pde
[0x200].PageFrameNumber
= PaToPfn(HAL_BASE
+ KERNEL_BASE_PHYS
);
215 /* Setup KUSER_SHARED_DATA Base */
216 PageDir
->Pde
[0x1F0].Valid
= 1;
217 PageDir
->Pde
[0x1F0].Write
= 1;
218 PageDir
->Pde
[0x1F0].PageFrameNumber
= 2;
221 PageDir
->Pde
[0x1FF].Valid
= 1;
222 PageDir
->Pde
[0x1FF].Write
= 1;
223 PageDir
->Pde
[0x1FF].PageFrameNumber
= 1;
228 LdrGetModuleObject(PCHAR ModuleName
)
232 for (i
= 0; i
< LoaderBlock
.ModsCount
; i
++)
234 if (strstr(_strupr((PCHAR
)reactos_modules
[i
].String
), _strupr(ModuleName
)))
236 return &reactos_modules
[i
];
245 LdrPEFixupForward(IN PCHAR ForwardName
)
247 CHAR NameBuffer
[128];
249 PLOADER_MODULE ModuleObject
;
251 strcpy(NameBuffer
, ForwardName
);
252 p
= strchr(NameBuffer
, '.');
253 if (p
== NULL
) return NULL
;
256 ModuleObject
= LdrGetModuleObject(NameBuffer
);
259 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer
);
263 return LdrPEGetExportByName((PVOID
)ModuleObject
->ModStart
, (PUCHAR
)(p
+ 1), 0xffff);
268 LdrPEGetExportByName(PVOID BaseAddress
,
272 PIMAGE_EXPORT_DIRECTORY ExportDir
;
273 PULONG
* ExFunctions
;
279 LONG minn
, maxn
, mid
, res
;
282 /* HAL and NTOS use a virtual address, switch it to physical mode */
283 if ((ULONG_PTR
)BaseAddress
& KSEG0_BASE
)
285 BaseAddress
= RVA(BaseAddress
, -KSEG0_BASE
);
288 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
289 RtlImageDirectoryEntryToData(BaseAddress
,
291 IMAGE_DIRECTORY_ENTRY_EXPORT
,
295 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
299 /* The symbol names may be missing entirely */
300 if (!ExportDir
->AddressOfNames
)
302 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
307 * Get header pointers
309 ExNames
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfNames
);
310 ExOrdinals
= (USHORT
*)RVA(BaseAddress
, ExportDir
->AddressOfNameOrdinals
);
311 ExFunctions
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfFunctions
);
314 * Check the hint first
316 if (Hint
< ExportDir
->NumberOfNames
)
318 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
319 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
321 Ordinal
= ExOrdinals
[Hint
];
322 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
323 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
324 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
326 Function
= LdrPEFixupForward((PCHAR
)Function
);
327 if (Function
== NULL
)
329 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function
);
334 if (Function
!= NULL
) return Function
;
342 maxn
= ExportDir
->NumberOfNames
- 1;
345 mid
= (minn
+ maxn
) / 2;
347 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
348 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
351 Ordinal
= ExOrdinals
[mid
];
352 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
353 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
354 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
356 Function
= LdrPEFixupForward((PCHAR
)Function
);
357 if (Function
== NULL
)
359 DbgPrint("1: failed to find %s\n", Function
);
363 if (Function
!= NULL
)
378 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
379 DbgPrint("2: failed to find %s\n",SymbolName
);
385 LdrPEProcessImportDirectoryEntry(PVOID DriverBase
,
386 PLOADER_MODULE LoaderModule
,
387 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
)
389 PVOID
* ImportAddressList
;
390 PULONG FunctionNameList
;
392 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->Name
== 0)
394 return STATUS_UNSUCCESSFUL
;
397 /* Get the import address list. */
398 ImportAddressList
= (PVOID
*)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
400 /* Get the list of functions to import. */
401 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
403 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->OriginalFirstThunk
);
407 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
410 /* Walk through function list and fixup addresses. */
411 while (*FunctionNameList
!= 0L)
413 if ((*FunctionNameList
) & 0x80000000)
415 DbgPrint("Failed to import ordinal from %s\n", LoaderModule
->String
);
416 return STATUS_UNSUCCESSFUL
;
420 IMAGE_IMPORT_BY_NAME
*pe_name
;
421 pe_name
= RVA(DriverBase
, *FunctionNameList
);
422 *ImportAddressList
= LdrPEGetExportByName((PVOID
)LoaderModule
->ModStart
, pe_name
->Name
, pe_name
->Hint
);
424 /* Fixup the address to be virtual */
425 *ImportAddressList
= RVA(*ImportAddressList
, KSEG0_BASE
);
427 //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
428 if ((*ImportAddressList
) == NULL
)
430 DbgPrint("Failed to import %s from %s\n", pe_name
->Name
, LoaderModule
->String
);
431 return STATUS_UNSUCCESSFUL
;
437 return STATUS_SUCCESS
;
440 extern BOOLEAN
FrLdrLoadDriver(PCHAR szFileName
, INT nPos
);
444 LdrPEGetOrLoadModule(IN PCHAR ModuleName
,
445 IN PCHAR ImportedName
,
446 IN PLOADER_MODULE
* ImportedModule
)
448 NTSTATUS Status
= STATUS_SUCCESS
;
450 *ImportedModule
= LdrGetModuleObject(ImportedName
);
451 if (*ImportedModule
== NULL
)
453 if (!FrLdrLoadDriver(ImportedName
, 0))
455 return STATUS_UNSUCCESSFUL
;
459 return LdrPEGetOrLoadModule
460 (ModuleName
, ImportedName
, ImportedModule
);
469 LdrPEFixupImports(IN PVOID DllBase
,
472 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
475 PLOADER_MODULE ImportedModule
;
478 /* Process each import module */
479 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
480 RtlImageDirectoryEntryToData(DllBase
,
482 IMAGE_DIRECTORY_ENTRY_IMPORT
,
484 while (ImportModuleDirectory
&& ImportModuleDirectory
->Name
)
486 /* Check to make sure that import lib is kernel */
487 ImportedName
= (PCHAR
) DllBase
+ ImportModuleDirectory
->Name
;
488 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
490 Status
= LdrPEGetOrLoadModule(DllName
, ImportedName
, &ImportedModule
);
491 if (!NT_SUCCESS(Status
)) return Status
;
493 Status
= LdrPEProcessImportDirectoryEntry(DllBase
, ImportedModule
, ImportModuleDirectory
);
494 if (!NT_SUCCESS(Status
)) return Status
;
496 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
497 ImportModuleDirectory
++;
500 return STATUS_SUCCESS
;
505 FrLdrReMapImage(IN PVOID Base
,
508 PIMAGE_NT_HEADERS NtHeader
;
509 PIMAGE_SECTION_HEADER Section
;
510 ULONG i
, Size
, DriverSize
= 0;
512 /* Get the first section */
513 NtHeader
= RtlImageNtHeader(Base
);
514 Section
= IMAGE_FIRST_SECTION(NtHeader
);
516 /* Allocate memory for the driver */
517 DriverSize
= NtHeader
->OptionalHeader
.SizeOfImage
;
518 LoadBase
= MmAllocateMemoryAtAddress(DriverSize
, LoadBase
);
521 /* Copy headers over */
522 RtlMoveMemory(LoadBase
, Base
, NtHeader
->OptionalHeader
.SizeOfHeaders
);
524 /* Copy image sections into virtual section */
525 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
527 /* Get the size of this section and check if it's valid */
528 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
529 if (Size
<= DriverSize
)
531 if (Section
[i
].SizeOfRawData
)
533 /* Copy the data from the disk to the image */
534 RtlCopyMemory((PVOID
)((ULONG_PTR
)LoadBase
+
535 Section
[i
].VirtualAddress
),
536 (PVOID
)((ULONG_PTR
)Base
+
537 Section
[i
].PointerToRawData
),
538 Section
[i
].Misc
.VirtualSize
>
539 Section
[i
].SizeOfRawData
?
540 Section
[i
].SizeOfRawData
:
541 Section
[i
].Misc
.VirtualSize
);
545 /* Clear the BSS area */
546 RtlZeroMemory((PVOID
)((ULONG_PTR
)LoadBase
+
547 Section
[i
].VirtualAddress
),
548 Section
[i
].Misc
.VirtualSize
);
553 /* Return the size of the mapped driver */
559 FrLdrMapImage(IN
FILE *Image
,
563 PVOID ImageBase
, LoadBase
, ReadBuffer
;
564 ULONG ImageId
= LoaderBlock
.ModsCount
;
566 NTSTATUS Status
= STATUS_SUCCESS
;
568 /* Try to see, maybe it's loaded already */
569 if (LdrGetModuleObject(Name
) != NULL
)
571 /* It's loaded, return NULL. It would be wise to return
572 correct LoadBase, but it seems to be ignored almost everywhere */
576 /* Set the virtual (image) and physical (load) addresses */
577 LoadBase
= (PVOID
)NextModuleBase
;
578 ImageBase
= RVA(LoadBase
, KSEG0_BASE
);
580 /* Save the Image Size */
581 ImageSize
= FsGetFileSize(Image
);
583 /* Set the file pointer to zero */
584 FsSetFilePointer(Image
, 0);
586 /* Allocate a temporary buffer for the read */
587 ReadBuffer
= MmAllocateMemory(ImageSize
);
589 /* Load the file image */
590 FsReadFile(Image
, ImageSize
, NULL
, ReadBuffer
);
592 /* Map it into virtual memory */
593 ImageSize
= FrLdrReMapImage(ReadBuffer
, LoadBase
);
595 /* Free the temporary buffer */
596 MmFreeMemory(ReadBuffer
);
598 /* Calculate Difference between Real Base and Compiled Base*/
599 Status
= LdrRelocateImageWithBias(LoadBase
,
600 (ULONG_PTR
)ImageBase
-
605 STATUS_UNSUCCESSFUL
);
606 if (!NT_SUCCESS(Status
))
609 DbgPrint("Failed to relocate image: %s\n", Name
);
613 /* Fill out Module Data Structure */
614 reactos_modules
[ImageId
].ModStart
= (ULONG_PTR
)ImageBase
;
615 reactos_modules
[ImageId
].ModEnd
= (ULONG_PTR
)ImageBase
+ ImageSize
;
616 strcpy(reactos_module_strings
[ImageId
], Name
);
617 reactos_modules
[ImageId
].String
= (ULONG_PTR
)reactos_module_strings
[ImageId
];
618 LoaderBlock
.ModsCount
++;
620 /* Increase the next Load Base */
621 NextModuleBase
= ROUND_UP(NextModuleBase
+ ImageSize
, PAGE_SIZE
);
623 /* Perform import fixups */
624 if (!NT_SUCCESS(LdrPEFixupImports(LoadBase
, Name
)))
626 /* Fixup failed, just don't include it in the list */
627 // NextModuleBase = OldNextModuleBase;
628 LoaderBlock
.ModsCount
= ImageId
;
632 /* Return the final mapped address */
638 FrLdrLoadModule(FILE *ModuleImage
,
642 ULONG LocalModuleSize
;
643 PLOADER_MODULE ModuleData
;
647 /* Get current module data structure and module name string array */
648 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
650 /* Get only the Module Name */
653 TempName
= strchr(ModuleName
, '\\');
656 ModuleName
= TempName
+ 1;
660 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
662 /* Get Module Size */
663 LocalModuleSize
= FsGetFileSize(ModuleImage
);
665 /* Fill out Module Data Structure */
666 ModuleData
->ModStart
= NextModuleBase
;
667 ModuleData
->ModEnd
= NextModuleBase
+ LocalModuleSize
;
670 strcpy(NameBuffer
, ModuleName
);
671 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
673 /* Load the file image */
674 FsReadFile(ModuleImage
, LocalModuleSize
, NULL
, (PVOID
)NextModuleBase
);
676 /* Move to next memory block and increase Module Count */
677 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
678 LoaderBlock
.ModsCount
++;
679 // DbgPrint("NextBase, ImageSize, ModStart, ModEnd %p %p %p %p\n",
680 // NextModuleBase, LocalModuleSize, ModuleData->ModStart, ModuleData->ModEnd);
682 /* Return Module Size if required */
683 if (ModuleSize
!= NULL
) {
684 *ModuleSize
= LocalModuleSize
;
687 return(ModuleData
->ModStart
);
692 FrLdrCreateModule(LPCSTR ModuleName
)
694 PLOADER_MODULE ModuleData
;
697 /* Get current module data structure and module name string array */
698 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
699 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
701 /* Set up the structure */
702 ModuleData
->ModStart
= NextModuleBase
;
703 ModuleData
->ModEnd
= -1;
706 strcpy(NameBuffer
, ModuleName
);
707 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
709 /* Set the current Module */
710 CurrentModule
= ModuleData
;
712 /* Return Module Base Address */
713 return(ModuleData
->ModStart
);
718 FrLdrCloseModule(ULONG_PTR ModuleBase
,
721 PLOADER_MODULE ModuleData
= CurrentModule
;
723 /* Make sure a module is opened */
726 /* Make sure this is the right module and that it hasn't been closed */
727 if ((ModuleBase
== ModuleData
->ModStart
) && (ModuleData
->ModEnd
== (ULONG_PTR
)-1)) {
729 /* Close the Module */
730 ModuleData
->ModEnd
= ModuleData
->ModStart
+ ModuleSize
;
732 /* Set the next Module Base and increase the number of modules */
733 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
734 LoaderBlock
.ModsCount
++;
736 /* Close the currently opened module */
737 CurrentModule
= NULL
;