#define PDE_SHIFT 20
#define PDE_SHIFT_PAE 18
-
+
/* Converts a Relative Address read from the Kernel into a Physical Address */
#define RaToPa(p) \
(ULONG_PTR)((ULONG_PTR)p + KERNEL_BASE_PHYS)
-
+
/* Converts a Phsyical Address Pointer into a Page Frame Number */
#define PaPtrToPfn(p) \
(((ULONG_PTR)&p) >> PFN_SHIFT)
-
+
/* Converts a Phsyical Address into a Page Frame Number */
#define PaToPfn(p) \
((p) >> PFN_SHIFT)
#define HYPERSPACE_BASE 0xF0800000
#define APIC_BASE 0xFEC00000
#define KPCR_BASE 0xFF000000
-
+
#define LowMemPageTableIndex 0
#define StartupPageTableIndex (STARTUP_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
#define HyperspacePageTableIndex (HYPERSPACE_BASE >> 20) / sizeof(HARDWARE_PTE_X86)
/* Kernel Entrypoint in Physical Memory */
ULONG_PTR KernelEntry;
-/* Page Directory and Tables for non-PAE Systems */
-extern ULONG_PTR startup_pagedirectory;
-extern ULONG_PTR lowmem_pagetable;
-extern ULONG_PTR kernel_pagetable;
-extern ULONG_PTR hyperspace_pagetable;
-extern ULONG_PTR _pae_pagedirtable;
-extern ULONG_PTR apic_pagetable;
-extern ULONG_PTR kpcr_pagetable;
-
-/* Page Directory and Tables for PAE Systems */
-extern ULONG_PTR startup_pagedirectorytable_pae;
-extern ULONG_PTR startup_pagedirectory_pae;
-extern ULONG_PTR lowmem_pagetable_pae;
-extern ULONG_PTR kernel_pagetable_pae;
-extern ULONG_PTR hyperspace_pagetable_pae;
-extern ULONG_PTR pagedirtable_pae;
-extern ULONG_PTR apic_pagetable_pae;
-extern ULONG_PTR kpcr_pagetable_pae;
-
typedef struct _HARDWARE_PTE_X86 {
ULONG Valid : 1;
ULONG Write : 1;
typedef struct _PAGE_DIRECTORY_X86 {
HARDWARE_PTE_X86 Pde[1024];
-} PAGE_DIRECTORY_x86, *PPAGE_DIRECTORY_X86;
+} PAGE_DIRECTORY_X86, *PPAGE_DIRECTORY_X86;
typedef struct _PAGE_DIRECTORY_X64 {
HARDWARE_PTE_X64 Pde[2048];
HARDWARE_PTE_X64 Pde[4];
} PAGE_DIRECTORY_TABLE_X64, *PPAGE_DIRECTORY_TABLE_X64;
+/* Page Directory and Tables for non-PAE Systems */
+extern PAGE_DIRECTORY_X86 startup_pagedirectory;
+extern PAGE_DIRECTORY_X86 lowmem_pagetable;
+extern PAGE_DIRECTORY_X86 kernel_pagetable;
+extern ULONG_PTR hyperspace_pagetable;
+extern ULONG_PTR _pae_pagedirtable;
+extern PAGE_DIRECTORY_X86 apic_pagetable;
+extern PAGE_DIRECTORY_X86 kpcr_pagetable;
+
+/* Page Directory and Tables for PAE Systems */
+extern PAGE_DIRECTORY_TABLE_X64 startup_pagedirectorytable_pae;
+extern PAGE_DIRECTORY_X64 startup_pagedirectory_pae;
+extern PAGE_DIRECTORY_X64 lowmem_pagetable_pae;
+extern PAGE_DIRECTORY_X64 kernel_pagetable_pae;
+extern ULONG_PTR hyperspace_pagetable_pae;
+extern ULONG_PTR pagedirtable_pae;
+extern PAGE_DIRECTORY_X64 apic_pagetable_pae;
+extern PAGE_DIRECTORY_X64 kpcr_pagetable_pae;
+
/* FUNCTIONS *****************************************************************/
/*++
- * FrLdrStartup
+ * FrLdrStartup
* INTERNAL
*
* Prepares the system for loading the Kernel.
VOID
STDCALL
FrLdrStartup(ULONG Magic)
-{
+{
/* Disable Interrupts */
Ke386DisableInterrupts();
-
+
/* Re-initalize EFLAGS */
Ke386EraseFlags();
-
- /* Get Kernel Base and Set MmSystemRangeStart */
- FrLdrGetKernelBase();
+ /* Get the PAE Mode */
FrLdrGetPaeMode();
-
+
/* Initialize the page directory */
FrLdrSetupPageDirectory();
-
+
/* Initialize Paging, Write-Protection and Load NTOSKRNL */
FrLdrSetupPae(Magic);
}
/*++
- * FrLdrSetupPae
+ * FrLdrSetupPae
* INTERNAL
*
* Configures PAE on a MP System, and sets the PDBR if it's supported, or if
if (PaeModeEnabled)
{
PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectorytable_pae;
-
+
/* Enable PAE */
Ke386SetCr4(Ke386GetCr4() | X86_CR4_PAE);
- }
-
+ }
+
/* Set the PDBR */
Ke386SetPageTableDirectory(PageDirectoryBaseAddress);
-
+
/* Enable Paging and Write Protect*/
Ke386SetCr0(Ke386GetCr0() | X86_CR0_PG | X86_CR0_WP);
-
+
/* Jump to Kernel */
PagedJump = (ASMCODE)KernelEntryPoint;
PagedJump(Magic, &LoaderBlock);
}
/*++
- * FrLdrGetKernelBase
+ * FrLdrGetKernelBase
* INTERNAL
*
* Gets the Kernel Base to use.
FrLdrGetKernelBase(VOID)
{
PCHAR p;
-
+
/* Read Command Line */
p = (PCHAR)LoaderBlock.CommandLine;
while ((p = strchr(p, '/')) != NULL) {
-
+
/* Find "/3GB" */
if (!strnicmp(p + 1, "3GB", 3)) {
-
+
/* Make sure there's nothing following it */
if (p[4] == ' ' || p[4] == 0) {
-
+
/* Use 3GB */
KernelBase = 0xC0000000;
}
p++;
}
-
+
/* Set KernelBase */
LoaderBlock.KernelBase = KernelBase;
}
/*++
- * FrLdrGetPaeMode
+ * FrLdrGetPaeMode
* INTERNAL
*
* Determines whether PAE mode shoudl be enabled or not.
}
/*++
- * FrLdrSetupPageDirectory
+ * FrLdrSetupPageDirectory
* INTERNAL
*
* Sets up the ReactOS Startup Page Directory.
ULONG i;
if (PaeModeEnabled) {
-
+
/* Get the Kernel Table Index */
KernelPageTableIndex = (KernelBase >> 21);
PageDirPae->Pde[KernelPageTableIndex + i].Write = 1;
PageDirPae->Pde[KernelPageTableIndex + i].PageFrameNumber = PaPtrToPfn(kernel_pagetable_pae) + i;
}
-
+
/* Set up the Startup PDE */
for (i = 0; i < 4; i++)
{
PageDirPae->Pde[StartupPageTableIndexPae + i].Write = 1;
PageDirPae->Pde[StartupPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(startup_pagedirectory_pae) + i;
}
-
+
/* Set up the Hyperspace PDE */
for (i = 0; i < 2; i++)
{
PageDirPae->Pde[HyperspacePageTableIndexPae + i].Write = 1;
PageDirPae->Pde[HyperspacePageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable_pae) + i;
}
-
- /* Set up the Apic PDE */
+
+ /* Set up the Apic PDE */
for (i = 0; i < 2; i++)
{
PageDirPae->Pde[ApicPageTableIndexPae + i].Valid = 1;
PageDirPae->Pde[ApicPageTableIndexPae + i].Write = 1;
PageDirPae->Pde[ApicPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(apic_pagetable_pae) + i;
}
-
+
/* Set up the KPCR PDE */
PageDirPae->Pde[KpcrPageTableIndexPae].Valid = 1;
PageDirPae->Pde[KpcrPageTableIndexPae].Write = 1;
PageDirPae->Pde[KpcrPageTableIndexPae].PageFrameNumber = PaPtrToPfn(kpcr_pagetable_pae);
-
+
/* Set up Low Memory PTEs */
PageDirPae = (PPAGE_DIRECTORY_X64)&lowmem_pagetable_pae;
for (i=0; i<1024; i++) {
-
+
PageDirPae->Pde[i].Valid = 1;
PageDirPae->Pde[i].Write = 1;
PageDirPae->Pde[i].Owner = 1;
PageDirPae->Pde[i].PageFrameNumber = i;
}
-
+
/* Set up Kernel PTEs */
PageDirPae = (PPAGE_DIRECTORY_X64)&kernel_pagetable_pae;
for (i=0; i<1536; i++) {
-
+
PageDirPae->Pde[i].Valid = 1;
PageDirPae->Pde[i].Write = 1;
PageDirPae->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS) + i;
}
-
+
/* Set up APIC PTEs */
PageDirPae = (PPAGE_DIRECTORY_X64)&apic_pagetable_pae;
PageDirPae->Pde[0].Valid = 1;
PageDirPae->Pde[0x200].CacheDisable = 1;
PageDirPae->Pde[0x200].WriteThrough = 1;
PageDirPae->Pde[0x200].PageFrameNumber = PaToPfn(APIC_BASE + KERNEL_BASE_PHYS);
-
+
/* Set up KPCR PTEs */
PageDirPae = (PPAGE_DIRECTORY_X64)&kpcr_pagetable_pae;
PageDirPae->Pde[0].Valid = 1;
PageDirPae->Pde[0].Write = 1;
- PageDirPae->Pde[0].PageFrameNumber = 1;
-
+ PageDirPae->Pde[0].PageFrameNumber = 1;
+
} else {
-
+
/* Get the Kernel Table Index */
KernelPageTableIndex = (KernelBase >> PDE_SHIFT) / sizeof(HARDWARE_PTE_X86);
-
+
/* Get the Startup Page Directory */
PageDir = (PPAGE_DIRECTORY_X86)&startup_pagedirectory;
-
+
/* Set up the Low Memory PDE */
PageDir->Pde[LowMemPageTableIndex].Valid = 1;
PageDir->Pde[LowMemPageTableIndex].Write = 1;
PageDir->Pde[LowMemPageTableIndex].PageFrameNumber = PaPtrToPfn(lowmem_pagetable);
-
+
/* Set up the Kernel PDEs */
PageDir->Pde[KernelPageTableIndex].Valid = 1;
PageDir->Pde[KernelPageTableIndex].Write = 1;
PageDir->Pde[KernelPageTableIndex + 1].Valid = 1;
PageDir->Pde[KernelPageTableIndex + 1].Write = 1;
PageDir->Pde[KernelPageTableIndex + 1].PageFrameNumber = PaPtrToPfn(kernel_pagetable + 4096);
-
+
/* Set up the Startup PDE */
PageDir->Pde[StartupPageTableIndex].Valid = 1;
PageDir->Pde[StartupPageTableIndex].Write = 1;
PageDir->Pde[StartupPageTableIndex].PageFrameNumber = PaPtrToPfn(startup_pagedirectory);
-
+
/* Set up the Hyperspace PDE */
PageDir->Pde[HyperspacePageTableIndex].Valid = 1;
PageDir->Pde[HyperspacePageTableIndex].Write = 1;
PageDir->Pde[HyperspacePageTableIndex].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable);
-
- /* Set up the Apic PDE */
+
+ /* Set up the Apic PDE */
PageDir->Pde[ApicPageTableIndex].Valid = 1;
PageDir->Pde[ApicPageTableIndex].Write = 1;
PageDir->Pde[ApicPageTableIndex].PageFrameNumber = PaPtrToPfn(apic_pagetable);
-
+
/* Set up the KPCR PDE */
PageDir->Pde[KpcrPageTableIndex].Valid = 1;
PageDir->Pde[KpcrPageTableIndex].Write = 1;
PageDir->Pde[KpcrPageTableIndex].PageFrameNumber = PaPtrToPfn(kpcr_pagetable);
-
+
/* Set up Low Memory PTEs */
PageDir = (PPAGE_DIRECTORY_X86)&lowmem_pagetable;
for (i=0; i<1024; i++) {
-
+
PageDir->Pde[i].Valid = 1;
PageDir->Pde[i].Write = 1;
PageDir->Pde[i].Owner = 1;
PageDir->Pde[i].PageFrameNumber = PaToPfn(i * PAGE_SIZE);
}
-
+
/* Set up Kernel PTEs */
PageDir = (PPAGE_DIRECTORY_X86)&kernel_pagetable;
for (i=0; i<1536; i++) {
-
+
PageDir->Pde[i].Valid = 1;
PageDir->Pde[i].Write = 1;
PageDir->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS + i * PAGE_SIZE);
}
-
+
/* Set up APIC PTEs */
PageDir = (PPAGE_DIRECTORY_X86)&apic_pagetable;
PageDir->Pde[0].Valid = 1;
PageDir->Pde[0x200].CacheDisable = 1;
PageDir->Pde[0x200].WriteThrough = 1;
PageDir->Pde[0x200].PageFrameNumber = PaToPfn(APIC_BASE + KERNEL_BASE_PHYS);
-
+
/* Set up KPCR PTEs */
PageDir = (PPAGE_DIRECTORY_X86)&kpcr_pagetable;
PageDir->Pde[0].Valid = 1;
PageDir->Pde[0].Write = 1;
- PageDir->Pde[0].PageFrameNumber = 1;
+ PageDir->Pde[0].PageFrameNumber = 1;
}
return;
}
/*++
- * FrLdrMapKernel
+ * FrLdrMapKernel
* INTERNAL
*
* Maps the Kernel into memory, does PE Section Mapping, initalizes the
ULONG_PTR TargetSection;
ULONG SectionSize;
LONG i;
+ PIMAGE_DATA_DIRECTORY RelocationDDir;
+ PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
+ ULONG Count;
+ ULONG_PTR Address, MaxAddress;
+ PUSHORT TypeOffset;
+ ULONG_PTR Delta;
+ PUSHORT ShortPtr;
+ PULONG LongPtr;
/* Allocate 1024 bytes for PE Header */
ImageHeader = (PIMAGE_DOS_HEADER)MmAllocateMemory(1024);
-
+
/* Make sure it was succesful */
if (ImageHeader == NULL) {
-
+
return FALSE;
}
/* Now read the MZ header to get the offset to the PE Header */
NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)ImageHeader + ImageHeader->e_lfanew);
-
- /* Save the Image Base */
+
+ /* Get Kernel Base */
KernelBase = NtHeader->OptionalHeader.ImageBase;
-
+ FrLdrGetKernelBase();
+
/* Save Entrypoint */
KernelEntry = RaToPa(NtHeader->OptionalHeader.AddressOfEntryPoint);
-
+
/* Save the Image Size */
ImageSize = NtHeader->OptionalHeader.SizeOfImage;
-
+
/* Free the Header */
MmFreeMemory(ImageHeader);
/* Load the file image */
FsReadFile(KernelImage, ImageSize, NULL, (PVOID)KERNEL_BASE_PHYS);
-
+
/* Reload the NT Header */
NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)KERNEL_BASE_PHYS + ImageHeader->e_lfanew);
-
+
/* Load the first section */
Section = IMAGE_FIRST_SECTION(NtHeader);
SectionCount = NtHeader->FileHeader.NumberOfSections - 1;
-
+
/* Now go to the last section */
Section += SectionCount;
-
- /* Walk each section backwards */
+
+ /* Walk each section backwards */
for (i=SectionCount; i >= 0; i--, Section--) {
-
- /* Get the disk location and the memory location, and the size */
+
+ /* Get the disk location and the memory location, and the size */
SourceSection = RaToPa(Section->PointerToRawData);
TargetSection = RaToPa(Section->VirtualAddress);
SectionSize = Section->SizeOfRawData;
-
+
/* If the section is already mapped correctly, go to the next */
if (SourceSection == TargetSection) continue;
-
+
/* Load it into memory */
memmove((PVOID)TargetSection, (PVOID)SourceSection, SectionSize);
-
+
/* Check for unitilizated data */
if (Section->SizeOfRawData < Section->Misc.VirtualSize) {
-
+
/* Zero it out */
- memset((PVOID)RaToPa(Section->VirtualAddress + Section->SizeOfRawData),
+ memset((PVOID)RaToPa(Section->VirtualAddress + Section->SizeOfRawData),
0,
Section->Misc.VirtualSize - Section->SizeOfRawData);
}
}
-
- /* Now relocate the file */
- /* FIXME: ADD RELOC CODE */
-
+
+ /* Get the Relocation Data Directory */
+ RelocationDDir = &NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+ /* Get the Relocation Section Start and End*/
+ RelocationDir = (PIMAGE_BASE_RELOCATION)(KERNEL_BASE_PHYS + RelocationDDir->VirtualAddress);
+ RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
+
+ /* Calculate Difference between Real Base and Compiled Base*/
+ Delta = KernelBase - NtHeader->OptionalHeader.ImageBase;
+
+ /* Determine how far we shoudl relocate */
+ MaxAddress = KERNEL_BASE_PHYS + ImageSize;
+
+ /* Relocate until we've processed all the blocks */
+ while (RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0) {
+
+ /* See how many Relocation Blocks we have */
+ Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
+
+ /* Calculate the Address of this Directory */
+ Address = KERNEL_BASE_PHYS + RelocationDir->VirtualAddress;
+
+ /* Calculate the Offset of the Type */
+ TypeOffset = (PUSHORT)(RelocationDir + 1);
+
+ for (i = 0; i < Count; i++) {
+
+ ShortPtr = (PUSHORT)(Address + (*TypeOffset & 0xFFF));
+
+ /* Don't relocate after the end of the loaded driver */
+ if ((ULONG_PTR)ShortPtr >= MaxAddress) break;
+
+ switch (*TypeOffset >> 12) {
+
+ case IMAGE_REL_BASED_ABSOLUTE:
+ break;
+
+ case IMAGE_REL_BASED_HIGH:
+ *ShortPtr += HIWORD(Delta);
+ break;
+
+ case IMAGE_REL_BASED_LOW:
+ *ShortPtr += LOWORD(Delta);
+ break;
+
+ case IMAGE_REL_BASED_HIGHLOW:
+ LongPtr = (PULONG)ShortPtr;
+ *LongPtr += Delta;
+ break;
+ }
+
+ TypeOffset++;
+ }
+
+ /* Move to the next Relocation Table */
+ RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
+ }
+
/* Increase the next Load Base */
NextModuleBase = ROUND_UP(KERNEL_BASE_PHYS + ImageSize, PAGE_SIZE);
ULONG_PTR
STDCALL
-FrLdrLoadModule(FILE *ModuleImage,
- LPSTR ModuleName,
+FrLdrLoadModule(FILE *ModuleImage,
+ LPSTR ModuleName,
PULONG ModuleSize)
{
ULONG LocalModuleSize;
/* Get current module data structure and module name string array */
ModuleData = &multiboot_modules[LoaderBlock.ModsCount];
-
+
/* Get only the Module Name */
do {
-
+
TempName = strchr(ModuleName, '\\');
-
+
if(TempName) {
ModuleName = TempName + 1;
}
/* Get Module Size */
LocalModuleSize = FsGetFileSize(ModuleImage);
-
+
/* Fill out Module Data Structure */
ModuleData->ModuleStart = NextModuleBase;
ModuleData->ModuleEnd = NextModuleBase + LocalModuleSize;
-
+
/* Save name */
strcpy(NameBuffer, ModuleName);
ModuleData->ModuleName = NameBuffer;
/* Set up the structure */
ModuleData->ModuleStart = NextModuleBase;
ModuleData->ModuleEnd = -1;
-
+
/* Copy the name */
strcpy(NameBuffer, ModuleName);
ModuleData->ModuleName = NameBuffer;
BOOL
STDCALL
-FrLdrCloseModule(ULONG_PTR ModuleBase,
+FrLdrCloseModule(ULONG_PTR ModuleBase,
ULONG ModuleSize)
{
PFRLDR_MODULE ModuleData = CurrentModule;
/* Make sure a module is opened */
if (ModuleData) {
-
+
/* Make sure this is the right module and that it hasn't been closed */
if ((ModuleBase == ModuleData->ModuleStart) && (ModuleData->ModuleEnd == -1)) {
-
+
/* Close the Module */
ModuleData->ModuleEnd = ModuleData->ModuleStart + ModuleSize;
/* Set the next Module Base and increase the number of modules */
NextModuleBase = ROUND_UP(ModuleData->ModuleEnd, PAGE_SIZE);
LoaderBlock.ModsCount++;
-
+
/* Close the currently opened module */
CurrentModule = NULL;