- Revert 24020 (good code, but buggy) and 24041 (bad code/revision).

- This gets us as far as 24061(+24048) for booting.

svn path=/trunk/; revision=24078
This commit is contained in:
Alex Ionescu
2006-09-12 05:21:27 +00:00
parent 4e03e0ec4a
commit 978da5c0af
5 changed files with 225 additions and 189 deletions
+111 -97
View File
@@ -1198,89 +1198,126 @@ LdrGetExportByName(PVOID BaseAddress,
return (PVOID)NULL;
}
/*++
* @name LdrpSetProtection
*
* Local routine, used to set or reset pages protection.
* Used during PE relocation process.
*
* @param BaseAddress
* Base address of the image.
*
* @param Protection
* FALSE to disable protection, TRUE to enable it
*
* @return Usual NTSTATUS.
*
* @remarks None.
*
*--*/
NTSTATUS
LdrpSetProtection(IN PVOID BaseAddress,
IN BOOLEAN Protection)
/**********************************************************************
* NAME LOCAL
* LdrPerformRelocations
*
* DESCRIPTION
* Relocate a DLL's memory image.
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* NOTE
*
*/
static NTSTATUS
LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
PVOID ImageBase)
{
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_SECTION_HEADER SectionHeader;
ULONG i;
PVOID Address;
SIZE_T Size;
NTSTATUS Status;
ULONG NewAccess, OldAccess;
PIMAGE_DATA_DIRECTORY RelocationDDir;
PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
ULONG Count, ProtectSize, OldProtect, OldProtect2;
PVOID Page, ProtectPage, ProtectPage2;
PUSHORT TypeOffset;
ULONG_PTR Delta;
NTSTATUS Status;
NtHeaders = RtlImageNtHeader(BaseAddress);
/* Ensure image is valid */
if (NtHeaders == NULL)
return STATUS_INVALID_IMAGE_FORMAT;
/* Get the first section header */
SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
/* Loop through every section */
for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++, SectionHeader++)
if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
{
/* If section has no data - just skip to the next section */
if (SectionHeader->SizeOfRawData == 0)
continue;
return STATUS_UNSUCCESSFUL;
}
/* We need to act only if section isn't RW */
if (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE))
RelocationDDir =
&NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
{
return STATUS_SUCCESS;
}
ProtectSize = PAGE_SIZE;
Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
RelocationDDir->VirtualAddress);
RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
RelocationDDir->VirtualAddress + RelocationDDir->Size);
while (RelocationDir < RelocationEnd &&
RelocationDir->SizeOfBlock > 0)
{
Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
sizeof(USHORT);
Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
TypeOffset = (PUSHORT)(RelocationDir + 1);
/* Unprotect the page(s) we're about to relocate. */
ProtectPage = Page;
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
PAGE_READWRITE,
&OldProtect);
if (!NT_SUCCESS(Status))
{
if (Protection)
DPRINT1("Failed to unprotect relocation target.\n");
return Status;
}
if (RelocationDir->VirtualAddress + PAGE_SIZE <
NTHeaders->OptionalHeader.SizeOfImage)
{
ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage2,
&ProtectSize,
PAGE_READWRITE,
&OldProtect2);
if (!NT_SUCCESS(Status))
{
/* Check if the section was also executable, then we should
give it PAGE_EXECUTE, otherwise just PAGE_READONLY */
NewAccess = (SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) ? PAGE_EXECUTE : PAGE_READONLY;
/* Also check caching */
NewAccess |= (SectionHeader->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) ? PAGE_NOCACHE : 0;
}
else
{
/* Set access to RW */
NewAccess = PAGE_READWRITE;
DPRINT1("Failed to unprotect relocation target (2).\n");
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
OldProtect,
&OldProtect);
return Status;
}
}
else
{
ProtectPage2 = NULL;
}
/* Get the address and size of the section, and set protectin accordingly */
Address = (PVOID)((ULONG_PTR)BaseAddress + SectionHeader->VirtualAddress);
Size = SectionHeader->SizeOfRawData;
RelocationDir = LdrProcessRelocationBlock((ULONG_PTR)Page,
Count,
TypeOffset,
Delta);
if (RelocationDir == NULL)
return STATUS_UNSUCCESSFUL;
Status = NtProtectVirtualMemory(NtCurrentProcess(),
&Address,
&Size,
NewAccess,
&OldAccess);
/* Restore old page protection. */
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage,
&ProtectSize,
OldProtect,
&OldProtect);
if (!NT_SUCCESS(Status))
return Status;
if (ProtectPage2 != NULL)
{
NtProtectVirtualMemory(NtCurrentProcess(),
&ProtectPage2,
&ProtectSize,
OldProtect2,
&OldProtect2);
}
}
/* Instruction cache should be flushed if we enabled protection */
if (Protection)
NtFlushInstructionCache(NtCurrentProcess(), NULL, 0);
return STATUS_SUCCESS;
return STATUS_SUCCESS;
}
static NTSTATUS
@@ -1861,32 +1898,12 @@ PEPFUNC LdrPEStartup (PVOID ImageBase,
if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
{
DPRINT("LDR: Performing relocations\n");
/* Remove protection */
Status = LdrpSetProtection(ImageBase, FALSE);
Status = LdrPerformRelocations(NTHeaders, ImageBase);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrpSetProtection() failed with Status=0x%08X\n", Status);
DPRINT1("LdrPerformRelocations() failed\n");
return NULL;
}
/* Relocate */
Status = LdrRelocateImageWithBias(ImageBase, 0, "", STATUS_SUCCESS,
STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrRelocateImageWithBias() failed with Status=0x%08X\n", Status);
return NULL;
}
/* Set protection back */
Status = LdrpSetProtection(ImageBase, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrpSetProtection() failed with Status=0x%08X\n", Status);
return NULL;
}
}
if (Module != NULL)
@@ -2061,13 +2078,10 @@ LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
{
DPRINT1("Relocating (%lx -> %p) %wZ\n",
NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
Status = LdrRelocateImageWithBias(ImageBase, 0, "", STATUS_SUCCESS,
STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT);
Status = LdrPerformRelocations(NtHeaders, ImageBase);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrRelocateImageWithBias() failed\n");
DPRINT1("LdrPerformRelocations() failed\n");
NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
NtClose (SectionHandle);
RtlFreeUnicodeString(&FullDosName);
+59 -81
View File
@@ -3,10 +3,8 @@
* FILE: lib/rtl/image.c
* PURPOSE: Image handling functions
* Relocate functions were previously located in
* ntoskrnl/ldr/loader.c and
* dll/ntdll/ldr/utils.c files
* PROGRAMMER: Eric Kohl + original authors from loader.c and utils.c file
* Aleksey Bragin
* ntoskrnl/ldr/loader.c
* PROGRAMMER: Eric Kohl + original authors from loader.c file
*/
/* INCLUDES *****************************************************************/
@@ -151,76 +149,12 @@ RtlImageRvaToVa (
(ULONG_PTR)Section->VirtualAddress);
}
PIMAGE_BASE_RELOCATION
LdrProcessRelocationBlockLongLong(
IN ULONG_PTR Address,
IN ULONG Count,
IN PUSHORT TypeOffset,
IN LONGLONG Delta
)
{
SHORT Offset;
USHORT Type;
USHORT i;
PUSHORT ShortPtr;
PULONG LongPtr;
for (i = 0; i < Count; i++)
{
Offset = *TypeOffset & 0xFFF;
Type = *TypeOffset >> 12;
ShortPtr = (PUSHORT)(RVA(Address, Offset));
/*
* Don't relocate within the relocation section itself.
* GCC/LD generates sometimes relocation records for the relocation section.
* This is a bug in GCC/LD.
* Fix for it disabled, since it was only in ntoskrnl and not in ntdll
*/
/*
if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
(ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
{*/
switch (Type)
{
/* case IMAGE_REL_BASED_SECTION : */
/* case IMAGE_REL_BASED_REL32 : */
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)RVA(Address, Offset);
*LongPtr += Delta;
break;
case IMAGE_REL_BASED_HIGHADJ:
case IMAGE_REL_BASED_MIPS_JMPADDR:
default:
DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, *TypeOffset);
return (PIMAGE_BASE_RELOCATION)NULL;
}
TypeOffset++;
}
return (PIMAGE_BASE_RELOCATION)TypeOffset;
}
ULONG
NTAPI
LdrRelocateImageWithBias(
IN PVOID BaseAddress,
IN LONGLONG AdditionalBias,
IN PCCH LoaderName,
IN PCCH LoaderName,
IN ULONG Success,
IN ULONG Conflict,
IN ULONG Invalid
@@ -229,10 +163,14 @@ LdrRelocateImageWithBias(
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_DATA_DIRECTORY RelocationDDir;
PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
ULONG Count;
ULONG_PTR Address;
ULONG Count, i;
PVOID Address;//, MaxAddress;
PUSHORT TypeOffset;
LONGLONG Delta;
ULONG_PTR Delta;
SHORT Offset;
USHORT Type;
PUSHORT ShortPtr;
PULONG LongPtr;
NtHeaders = RtlImageNtHeader(BaseAddress);
@@ -254,24 +192,64 @@ LdrRelocateImageWithBias(
Delta = (ULONG_PTR)BaseAddress - NtHeaders->OptionalHeader.ImageBase + AdditionalBias;
RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + RelocationDDir->VirtualAddress);
RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
//MaxAddress = RVA(BaseAddress, DriverSize);
while (RelocationDir < RelocationEnd &&
RelocationDir->SizeOfBlock > 0)
{
Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
Address = (ULONG_PTR)RVA(BaseAddress, RelocationDir->VirtualAddress);
Address = RVA(BaseAddress, RelocationDir->VirtualAddress);
TypeOffset = (PUSHORT)(RelocationDir + 1);
RelocationDir = LdrProcessRelocationBlockLongLong(Address,
Count,
TypeOffset,
Delta);
if (RelocationDir == NULL)
for (i = 0; i < Count; i++)
{
DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
return Invalid;
Offset = *TypeOffset & 0xFFF;
Type = *TypeOffset >> 12;
ShortPtr = (PUSHORT)(RVA(Address, Offset));
/* Don't relocate after the end of the loaded driver */
/*if ((PVOID)ShortPtr >= MaxAddress)
{
break;
}*/
/*
* Don't relocate within the relocation section itself.
* GCC/LD generates sometimes relocation records for the relocation section.
* This is a bug in GCC/LD.
*/
if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
(ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
{
switch (Type)
{
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;
case IMAGE_REL_BASED_HIGHADJ:
case IMAGE_REL_BASED_MIPS_JMPADDR:
default:
DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, *TypeOffset);
return Invalid;
}
}
TypeOffset++;
}
RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
}
return Success;
+47 -11
View File
@@ -1,15 +1,54 @@
#ifndef __NTOSKRNL_INCLUDE_INTERNAL_PO_H
#define __NTOSKRNL_INCLUDE_INTERNAL_PO_H
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/include/po.h
* PURPOSE: Internal header for the Power Manager
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
extern PDEVICE_NODE PopSystemPowerDeviceNode;
//
// Define this if you want debugging support
//
#define _PO_DEBUG_ 0x00
//
// These define the Debug Masks Supported
//
#define PO_STATE_DEBUG 0x01
//
// Debug/Tracing support
//
#if _PO_DEBUG_
#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
#define POTRACE DbgPrintEx
#else
#define POTRACE(x, ...) \
if (x & PopTraceLevel) DbgPrint(__VA_ARGS__)
#endif
#else
#define POTRACE(x, ...) DPRINT(__VA_ARGS__)
#endif
//
// Initialization routines
//
VOID
NTAPI
PoInit(
PROS_LOADER_PARAMETER_BLOCK LoaderBlock,
PROS_LOADER_PARAMETER_BLOCK LoaderBlock,
BOOLEAN ForceAcpiDisable
);
VOID
NTAPI
PoInitializePrcb(
IN PKPRCB Prcb
);
//
// Power State routines
//
NTSTATUS
NTAPI
PopSetSystemPowerState(
@@ -22,10 +61,7 @@ PopCleanupPowerState(
IN PPOWER_STATE PowerState
);
VOID
NTAPI
PoInitializePrcb(
IN PKPRCB Prcb
);
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_PO_H */
//
// Global data inside the Power Manager
//
extern PDEVICE_NODE PopSystemPowerDeviceNode;
+6
View File
@@ -697,6 +697,12 @@ KeInitThread(IN OUT PKTHREAD Thread,
Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE;
Thread->KernelStackResident = TRUE;
/* ROS Mm HACK */
MmUpdatePageDir((PEPROCESS)Process,
(PVOID)Thread->StackLimit,
KERNEL_STACK_SIZE);
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
/* Enter SEH to avoid crashes due to user mode */
Status = STATUS_SUCCESS;
_SEH_TRY
+2
View File
@@ -150,6 +150,8 @@ KiDispatchThreadNoLock(ULONG NewThreadStatus)
KiIdleSummary |= Affinity;
}
MmUpdatePageDir((PEPROCESS)PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
/* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
DPRINT("You are : %x, swapping to: %x.\n", OldThread, CurrentThread);
ApcState = KiSwapContext(OldThread, CurrentThread);