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 ROS_KERNEL_ENTRY_POINT 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
;
113 __writecr3(PageDirectoryBaseAddress
);
115 /* Enable Paging and Write Protect*/
116 __writecr0(__readcr0() | X86_CR0_PG
| X86_CR0_WP
);
119 (*KernelEntryPoint
)(Magic
, &LoaderBlock
);
123 * FrLdrSetupPageDirectory
126 * Sets up the ReactOS Startup Page Directory.
135 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
136 * As such, please note that PageFrameNumber == PageEntryNumber.
141 FrLdrSetupPageDirectory(VOID
)
143 PPAGE_DIRECTORY_X86 PageDir
;
144 ULONG KernelPageTableIndex
;
147 /* Get the Kernel Table Index */
148 KernelPageTableIndex
= KernelBase
>> PDE_SHIFT
;
150 /* Get the Startup Page Directory */
151 PageDir
= (PPAGE_DIRECTORY_X86
)&startup_pagedirectory
;
153 /* Set up the Low Memory PDE */
154 PageDir
->Pde
[LowMemPageTableIndex
].Valid
= 1;
155 PageDir
->Pde
[LowMemPageTableIndex
].Write
= 1;
156 PageDir
->Pde
[LowMemPageTableIndex
].PageFrameNumber
= PaPtrToPfn(lowmem_pagetable
);
158 /* Set up the Kernel PDEs */
159 PageDir
->Pde
[KernelPageTableIndex
].Valid
= 1;
160 PageDir
->Pde
[KernelPageTableIndex
].Write
= 1;
161 PageDir
->Pde
[KernelPageTableIndex
].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
);
162 PageDir
->Pde
[KernelPageTableIndex
+ 1].Valid
= 1;
163 PageDir
->Pde
[KernelPageTableIndex
+ 1].Write
= 1;
164 PageDir
->Pde
[KernelPageTableIndex
+ 1].PageFrameNumber
= PaPtrToPfn(kernel_pagetable
+ 4096);
166 /* Set up the Startup PDE */
167 PageDir
->Pde
[StartupPageTableIndex
].Valid
= 1;
168 PageDir
->Pde
[StartupPageTableIndex
].Write
= 1;
169 PageDir
->Pde
[StartupPageTableIndex
].PageFrameNumber
= PaPtrToPfn(startup_pagedirectory
);
171 /* Set up the Hyperspace PDE */
172 PageDir
->Pde
[HyperspacePageTableIndex
].Valid
= 1;
173 PageDir
->Pde
[HyperspacePageTableIndex
].Write
= 1;
174 PageDir
->Pde
[HyperspacePageTableIndex
].PageFrameNumber
= PaPtrToPfn(hyperspace_pagetable
);
176 /* Set up the HAL PDE */
177 PageDir
->Pde
[HalPageTableIndex
].Valid
= 1;
178 PageDir
->Pde
[HalPageTableIndex
].Write
= 1;
179 PageDir
->Pde
[HalPageTableIndex
].PageFrameNumber
= PaPtrToPfn(apic_pagetable
);
181 /* Set up Low Memory PTEs */
182 PageDir
= (PPAGE_DIRECTORY_X86
)&lowmem_pagetable
;
183 for (i
=0; i
<1024; i
++)
185 PageDir
->Pde
[i
].Valid
= 1;
186 PageDir
->Pde
[i
].Write
= 1;
187 PageDir
->Pde
[i
].Owner
= 1;
188 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(i
* PAGE_SIZE
);
191 /* Set up Kernel PTEs */
192 PageDir
= (PPAGE_DIRECTORY_X86
)&kernel_pagetable
;
193 for (i
=0; i
<1536; i
++)
195 PageDir
->Pde
[i
].Valid
= 1;
196 PageDir
->Pde
[i
].Write
= 1;
197 PageDir
->Pde
[i
].PageFrameNumber
= PaToPfn(KERNEL_BASE_PHYS
+ i
* PAGE_SIZE
);
200 /* Setup APIC Base */
201 PageDir
= (PPAGE_DIRECTORY_X86
)&apic_pagetable
;
202 PageDir
->Pde
[0].Valid
= 1;
203 PageDir
->Pde
[0].Write
= 1;
204 PageDir
->Pde
[0].CacheDisable
= 1;
205 PageDir
->Pde
[0].WriteThrough
= 1;
206 PageDir
->Pde
[0].PageFrameNumber
= PaToPfn(HAL_BASE
);
207 PageDir
->Pde
[0x200].Valid
= 1;
208 PageDir
->Pde
[0x200].Write
= 1;
209 PageDir
->Pde
[0x200].CacheDisable
= 1;
210 PageDir
->Pde
[0x200].WriteThrough
= 1;
211 PageDir
->Pde
[0x200].PageFrameNumber
= PaToPfn(HAL_BASE
+ KERNEL_BASE_PHYS
);
213 /* Setup KUSER_SHARED_DATA Base */
214 PageDir
->Pde
[0x1F0].Valid
= 1;
215 PageDir
->Pde
[0x1F0].Write
= 1;
216 PageDir
->Pde
[0x1F0].PageFrameNumber
= 2;
219 PageDir
->Pde
[0x1FF].Valid
= 1;
220 PageDir
->Pde
[0x1FF].Write
= 1;
221 PageDir
->Pde
[0x1FF].PageFrameNumber
= 1;
226 LdrGetModuleObject(PCHAR ModuleName
)
230 for (i
= 0; i
< LoaderBlock
.ModsCount
; i
++)
232 if (strstr(_strupr((PCHAR
)reactos_modules
[i
].String
), _strupr(ModuleName
)))
234 return &reactos_modules
[i
];
243 LdrPEFixupForward(IN PCHAR ForwardName
)
245 CHAR NameBuffer
[128];
247 PLOADER_MODULE ModuleObject
;
249 strcpy(NameBuffer
, ForwardName
);
250 p
= strchr(NameBuffer
, '.');
251 if (p
== NULL
) return NULL
;
254 ModuleObject
= LdrGetModuleObject(NameBuffer
);
257 DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer
);
261 return LdrPEGetExportByName((PVOID
)ModuleObject
->ModStart
, (PUCHAR
)(p
+ 1), 0xffff);
266 LdrPEGetExportByName(PVOID BaseAddress
,
270 PIMAGE_EXPORT_DIRECTORY ExportDir
;
271 PULONG
* ExFunctions
;
277 LONG minn
, maxn
, mid
, res
;
280 /* HAL and NTOS use a virtual address, switch it to physical mode */
281 if ((ULONG_PTR
)BaseAddress
& KSEG0_BASE
)
283 BaseAddress
= RVA(BaseAddress
, -KSEG0_BASE
);
286 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
287 RtlImageDirectoryEntryToData(BaseAddress
,
289 IMAGE_DIRECTORY_ENTRY_EXPORT
,
293 DbgPrint("LdrPEGetExportByName(): no export directory!\n");
297 /* The symbol names may be missing entirely */
298 if (!ExportDir
->AddressOfNames
)
300 DbgPrint("LdrPEGetExportByName(): symbol names missing entirely\n");
305 * Get header pointers
307 ExNames
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfNames
);
308 ExOrdinals
= (USHORT
*)RVA(BaseAddress
, ExportDir
->AddressOfNameOrdinals
);
309 ExFunctions
= (PULONG
*)RVA(BaseAddress
, ExportDir
->AddressOfFunctions
);
312 * Check the hint first
314 if (Hint
< ExportDir
->NumberOfNames
)
316 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
317 if (strcmp(ExName
, (PCHAR
)SymbolName
) == 0)
319 Ordinal
= ExOrdinals
[Hint
];
320 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
321 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
322 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
324 Function
= LdrPEFixupForward((PCHAR
)Function
);
325 if (Function
== NULL
)
327 DbgPrint("LdrPEGetExportByName(): failed to find %s\n", Function
);
332 if (Function
!= NULL
) return Function
;
340 maxn
= ExportDir
->NumberOfNames
- 1;
343 mid
= (minn
+ maxn
) / 2;
345 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
346 res
= strcmp(ExName
, (PCHAR
)SymbolName
);
349 Ordinal
= ExOrdinals
[mid
];
350 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
351 if ((ULONG_PTR
)Function
>= (ULONG_PTR
)ExportDir
&&
352 (ULONG_PTR
)Function
< (ULONG_PTR
)ExportDir
+ ExportDirSize
)
354 Function
= LdrPEFixupForward((PCHAR
)Function
);
355 if (Function
== NULL
)
357 DbgPrint("1: failed to find %s\n", Function
);
361 if (Function
!= NULL
)
376 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
377 DbgPrint("2: failed to find %s\n",SymbolName
);
383 LdrPEProcessImportDirectoryEntry(PVOID DriverBase
,
384 PLOADER_MODULE LoaderModule
,
385 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
)
387 PVOID
* ImportAddressList
;
388 PULONG FunctionNameList
;
390 if (ImportModuleDirectory
== NULL
|| ImportModuleDirectory
->Name
== 0)
392 return STATUS_UNSUCCESSFUL
;
395 /* Get the import address list. */
396 ImportAddressList
= (PVOID
*)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
398 /* Get the list of functions to import. */
399 if (ImportModuleDirectory
->OriginalFirstThunk
!= 0)
401 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->OriginalFirstThunk
);
405 FunctionNameList
= (PULONG
)RVA(DriverBase
, ImportModuleDirectory
->FirstThunk
);
408 /* Walk through function list and fixup addresses. */
409 while (*FunctionNameList
!= 0L)
411 if ((*FunctionNameList
) & 0x80000000)
413 DbgPrint("Failed to import ordinal from %s\n", LoaderModule
->String
);
414 return STATUS_UNSUCCESSFUL
;
418 IMAGE_IMPORT_BY_NAME
*pe_name
;
419 pe_name
= RVA(DriverBase
, *FunctionNameList
);
420 *ImportAddressList
= LdrPEGetExportByName((PVOID
)LoaderModule
->ModStart
, pe_name
->Name
, pe_name
->Hint
);
422 /* Fixup the address to be virtual */
423 *ImportAddressList
= RVA(*ImportAddressList
, KSEG0_BASE
);
425 //DbgPrint("Looked for: %s and found: %p\n", pe_name->Name, *ImportAddressList);
426 if ((*ImportAddressList
) == NULL
)
428 DbgPrint("Failed to import %s from %s\n", pe_name
->Name
, LoaderModule
->String
);
429 return STATUS_UNSUCCESSFUL
;
435 return STATUS_SUCCESS
;
438 extern BOOLEAN
FrLdrLoadDriver(PCHAR szFileName
, INT nPos
);
442 LdrPEGetOrLoadModule(IN PCHAR ModuleName
,
443 IN PCHAR ImportedName
,
444 IN PLOADER_MODULE
* ImportedModule
)
446 NTSTATUS Status
= STATUS_SUCCESS
;
448 *ImportedModule
= LdrGetModuleObject(ImportedName
);
449 if (*ImportedModule
== NULL
)
451 if (!FrLdrLoadDriver(ImportedName
, 0))
453 return STATUS_UNSUCCESSFUL
;
457 return LdrPEGetOrLoadModule
458 (ModuleName
, ImportedName
, ImportedModule
);
467 LdrPEFixupImports(IN PVOID DllBase
,
470 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory
;
473 PLOADER_MODULE ImportedModule
;
476 /* Process each import module */
477 ImportModuleDirectory
= (PIMAGE_IMPORT_DESCRIPTOR
)
478 RtlImageDirectoryEntryToData(DllBase
,
480 IMAGE_DIRECTORY_ENTRY_IMPORT
,
482 while (ImportModuleDirectory
&& ImportModuleDirectory
->Name
)
484 /* Check to make sure that import lib is kernel */
485 ImportedName
= (PCHAR
) DllBase
+ ImportModuleDirectory
->Name
;
486 //DbgPrint("Processing imports for file: %s into file: %s\n", DllName, ImportedName);
488 Status
= LdrPEGetOrLoadModule(DllName
, ImportedName
, &ImportedModule
);
489 if (!NT_SUCCESS(Status
)) return Status
;
491 Status
= LdrPEProcessImportDirectoryEntry(DllBase
, ImportedModule
, ImportModuleDirectory
);
492 if (!NT_SUCCESS(Status
)) return Status
;
494 //DbgPrint("Imports for file: %s into file: %s complete\n", DllName, ImportedName);
495 ImportModuleDirectory
++;
498 return STATUS_SUCCESS
;
503 FrLdrReMapImage(IN PVOID Base
,
506 PIMAGE_NT_HEADERS NtHeader
;
507 PIMAGE_SECTION_HEADER Section
;
508 ULONG i
, Size
, DriverSize
= 0;
510 /* Get the first section */
511 NtHeader
= RtlImageNtHeader(Base
);
512 Section
= IMAGE_FIRST_SECTION(NtHeader
);
514 /* Allocate memory for the driver */
515 DriverSize
= NtHeader
->OptionalHeader
.SizeOfImage
;
516 LoadBase
= MmAllocateMemoryAtAddress(DriverSize
, LoadBase
, LoaderSystemCode
);
519 /* Copy headers over */
520 RtlMoveMemory(LoadBase
, Base
, NtHeader
->OptionalHeader
.SizeOfHeaders
);
522 /* Copy image sections into virtual section */
523 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
525 /* Get the size of this section and check if it's valid */
526 Size
= Section
[i
].VirtualAddress
+ Section
[i
].Misc
.VirtualSize
;
527 if (Size
<= DriverSize
)
529 if (Section
[i
].SizeOfRawData
)
531 /* Copy the data from the disk to the image */
532 RtlCopyMemory((PVOID
)((ULONG_PTR
)LoadBase
+
533 Section
[i
].VirtualAddress
),
534 (PVOID
)((ULONG_PTR
)Base
+
535 Section
[i
].PointerToRawData
),
536 Section
[i
].Misc
.VirtualSize
>
537 Section
[i
].SizeOfRawData
?
538 Section
[i
].SizeOfRawData
:
539 Section
[i
].Misc
.VirtualSize
);
543 /* Clear the BSS area */
544 RtlZeroMemory((PVOID
)((ULONG_PTR
)LoadBase
+
545 Section
[i
].VirtualAddress
),
546 Section
[i
].Misc
.VirtualSize
);
551 /* Return the size of the mapped driver */
557 FrLdrMapImage(IN
FILE *Image
,
561 PVOID ImageBase
, LoadBase
, ReadBuffer
;
562 ULONG ImageId
= LoaderBlock
.ModsCount
;
564 NTSTATUS Status
= STATUS_SUCCESS
;
566 /* Try to see, maybe it's loaded already */
567 if (LdrGetModuleObject(Name
) != NULL
)
569 /* It's loaded, return NULL. It would be wise to return
570 correct LoadBase, but it seems to be ignored almost everywhere */
574 /* Set the virtual (image) and physical (load) addresses */
575 LoadBase
= (PVOID
)NextModuleBase
;
576 ImageBase
= RVA(LoadBase
, KSEG0_BASE
);
578 /* Save the Image Size */
579 ImageSize
= FsGetFileSize(Image
);
581 /* Set the file pointer to zero */
582 FsSetFilePointer(Image
, 0);
584 /* Allocate a temporary buffer for the read */
585 ReadBuffer
= MmHeapAlloc(ImageSize
);
587 /* Load the file image */
588 FsReadFile(Image
, ImageSize
, NULL
, ReadBuffer
);
590 /* Map it into virtual memory */
591 ImageSize
= FrLdrReMapImage(ReadBuffer
, LoadBase
);
593 /* Free the temporary buffer */
594 MmHeapFree(ReadBuffer
);
596 /* Calculate Difference between Real Base and Compiled Base*/
597 Status
= LdrRelocateImageWithBias(LoadBase
,
598 (ULONG_PTR
)ImageBase
-
603 STATUS_UNSUCCESSFUL
);
604 if (!NT_SUCCESS(Status
))
607 DbgPrint("Failed to relocate image: %s\n", Name
);
611 /* Fill out Module Data Structure */
612 reactos_modules
[ImageId
].ModStart
= (ULONG_PTR
)ImageBase
;
613 reactos_modules
[ImageId
].ModEnd
= (ULONG_PTR
)ImageBase
+ ImageSize
;
614 strcpy(reactos_module_strings
[ImageId
], Name
);
615 reactos_modules
[ImageId
].String
= (ULONG_PTR
)reactos_module_strings
[ImageId
];
616 LoaderBlock
.ModsCount
++;
618 /* Increase the next Load Base */
619 NextModuleBase
= ROUND_UP(NextModuleBase
+ ImageSize
, PAGE_SIZE
);
621 /* Perform import fixups */
622 if (!NT_SUCCESS(LdrPEFixupImports(LoadBase
, Name
)))
624 /* Fixup failed, just don't include it in the list */
625 // NextModuleBase = OldNextModuleBase;
626 LoaderBlock
.ModsCount
= ImageId
;
630 /* Return the final mapped address */
636 FrLdrLoadModule(FILE *ModuleImage
,
640 ULONG LocalModuleSize
;
641 PLOADER_MODULE ModuleData
;
645 /* Get current module data structure and module name string array */
646 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
648 /* Get only the Module Name */
651 TempName
= strchr(ModuleName
, '\\');
654 ModuleName
= TempName
+ 1;
658 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
660 /* Get Module Size */
661 LocalModuleSize
= FsGetFileSize(ModuleImage
);
663 /* Fill out Module Data Structure */
664 ModuleData
->ModStart
= NextModuleBase
;
665 ModuleData
->ModEnd
= NextModuleBase
+ LocalModuleSize
;
668 strcpy(NameBuffer
, ModuleName
);
669 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
671 /* Load the file image */
672 FsReadFile(ModuleImage
, LocalModuleSize
, NULL
, (PVOID
)NextModuleBase
);
674 /* Move to next memory block and increase Module Count */
675 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
676 LoaderBlock
.ModsCount
++;
677 // DbgPrint("NextBase, ImageSize, ModStart, ModEnd %p %p %p %p\n",
678 // NextModuleBase, LocalModuleSize, ModuleData->ModStart, ModuleData->ModEnd);
680 /* Return Module Size if required */
681 if (ModuleSize
!= NULL
) {
682 *ModuleSize
= LocalModuleSize
;
685 return(ModuleData
->ModStart
);
690 FrLdrCreateModule(LPCSTR ModuleName
)
692 PLOADER_MODULE ModuleData
;
695 /* Get current module data structure and module name string array */
696 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
697 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
699 /* Set up the structure */
700 ModuleData
->ModStart
= NextModuleBase
;
701 ModuleData
->ModEnd
= -1;
704 strcpy(NameBuffer
, ModuleName
);
705 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
707 /* Set the current Module */
708 CurrentModule
= ModuleData
;
710 /* Return Module Base Address */
711 return(ModuleData
->ModStart
);
716 FrLdrCloseModule(ULONG_PTR ModuleBase
,
719 PLOADER_MODULE ModuleData
= CurrentModule
;
721 /* Make sure a module is opened */
724 /* Make sure this is the right module and that it hasn't been closed */
725 if ((ModuleBase
== ModuleData
->ModStart
) && (ModuleData
->ModEnd
== (ULONG_PTR
)-1)) {
727 /* Close the Module */
728 ModuleData
->ModEnd
= ModuleData
->ModStart
+ ModuleSize
;
730 /* Set the next Module Base and increase the number of modules */
731 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
732 LoaderBlock
.ModsCount
++;
734 /* Close the currently opened module */
735 CurrentModule
= NULL
;