Alex Ionescu <ionucu(a)videotron.ca>
Relocate kernel if the /3GB switch is supplied in kernel parameters.
Modified: trunk/reactos/boot/freeldr/freeldr/multiboot.c
_____
Modified: trunk/reactos/boot/freeldr/freeldr/multiboot.c
--- trunk/reactos/boot/freeldr/freeldr/multiboot.c 2005-03-11
23:13:03 UTC (rev 13940)
+++ trunk/reactos/boot/freeldr/freeldr/multiboot.c 2005-03-11
23:38:59 UTC (rev 13941)
@@ -164,9 +164,7 @@
/* Re-initalize EFLAGS */
Ke386EraseFlags();
- /* Get Kernel Base and Set MmSystemRangeStart */
- FrLdrGetKernelBase();
-
+ /* Get the PAE Mode */
FrLdrGetPaeMode();
/* Initialize the page directory */
@@ -531,6 +529,14 @@
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);
@@ -552,8 +558,9 @@
/* 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 */
- KernelBase = NtHeader->OptionalHeader.ImageBase;
+ /* Get Kernel Base */
+ KernelBase = NtHeader->OptionalHeader.ImageBase;
+ FrLdrGetKernelBase();
/* Save Entrypoint */
KernelEntry = RaToPa(NtHeader->OptionalHeader.AddressOfEntryPoint);
@@ -603,10 +610,65 @@
Section->Misc.VirtualSize - Section->SizeOfRawData);
}
}
+
+ /* Get the Relocation Data Directory */
+ RelocationDDir =
&NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
;
- /* Now relocate the file */
- /* FIXME: ADD RELOC CODE */
+ /* 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);