- Implement support for reading and writing physical memory for KD. The implementation uses a reserved mapping page to map the target physical address to. On x86 this page is located at virtual address 0xFFBFF000, and the PTE for this page is the last PTE of the nonpaged pool's PDE. Other architectures may need to reserve the PTE elsewhere.

- The physical memory support relies on several Mm variables and structures to be properly set up. Add a new flag, MiDbgReadyForPhysical, and set it when the debugger support can handle physical memory requests.
- Protect this page with a Memory Area to make the old Mm keep its dirty hands off it.
- Does not support I/O space or cache flags yet.
- Add generic KeInvalidateTlbEntry to invalidate a single TLB entry for a given address instead of flushing the whole TLB. Used by the debugger physical memory support as invalidating the whole TLB for every map and unmap of its debug PTE would incur significant overhead for large copies. Replace direct usage of __invlpg() with this in x86 code too.
- Fix incorrect cache flag check and set in KdpRead/WritePhysicalmemory for write combined requests. The debugger's Uncached flag was checked instead of the Write Combined flag, and the debuggers Write Combine number (0x3) was set instead of Mm's flag (0x20).
- Fix implementation of MmIsAddressValid (at least for x86; other architectures will need more checks). Just check the Address' PDE and PTE valid bits instead of using Memory Areas.
- Add missing ASSERTs to ensure the Memory Areas for paged pool, the PCR page, and the Shared User Data page are created.
- Add missing Memory Area for the 2 pages HAL currently uses for its own mappings on x86 -- previously, those pages could have been allocated by other parts of the OS, which would have resulted in serious corruptions.

svn path=/trunk/; revision=43960
This commit is contained in:
Stefan Ginsberg 2009-11-04 22:40:18 +00:00
parent 7909bd0733
commit 1d161cccdd
11 changed files with 365 additions and 110 deletions

View File

@ -3,7 +3,7 @@
FORCEINLINE
VOID
KeArmHaltProcessor(void)
KeArmHaltProcessor(VOID)
{
//
// Enter Wait-For-Interrupt Mode

View File

@ -40,6 +40,17 @@
//
//#define KeGetTrapFrameInterruptState(TrapFrame) \
//
// Invalidates the TLB entry for a specified address
//
FORCEINLINE
VOID
KeInvalidateTlbEntry(IN PVOID Address)
{
/* Invalidate the TLB entry for this address */
KeArmInvalidateTlbEntry(Address);
}
VOID
KiPassiveRelease(
VOID

View File

@ -42,6 +42,17 @@ extern ULONG Ke386CacheAlignment;
#define KeGetTrapFrameInterruptState(TrapFrame) \
BooleanFlagOn((TrapFrame)->EFlags, EFLAGS_INTERRUPT_MASK)
//
// Invalidates the TLB entry for a specified address
//
FORCEINLINE
VOID
KeInvalidateTlbEntry(IN PVOID Address)
{
/* Invalidate the TLB entry for this address */
__invlpg(Address);
}
VOID
FASTCALL
Ki386InitializeTss(

View File

@ -45,6 +45,8 @@ extern SIZE_T MmPagedPoolCommit;
extern SIZE_T MmPeakCommitment;
extern SIZE_T MmtotalCommitLimitMaximum;
extern BOOLEAN MiDbgReadyForPhysical;
struct _KTRAP_FRAME;
struct _EPROCESS;
struct _MM_RMAP_ENTRY;
@ -67,8 +69,11 @@ typedef ULONG PFN_TYPE, *PPFN_TYPE;
//
#define MMDBG_COPY_MAX_SIZE 0x8
#define MI_STATIC_MEMORY_AREAS (12)
#if defined(_X86_)
#define MI_STATIC_MEMORY_AREAS (14)
#else
#define MI_STATIC_MEMORY_AREAS (13)
#endif
#define MEMORY_AREA_INVALID (0)
#define MEMORY_AREA_SECTION_VIEW (1)

View File

@ -47,14 +47,14 @@ KdpPhysMap(ULONG_PTR PhysAddr, LONG Len)
PointerPte = MiAddressToPte(MI_KDBG_TMP_PAGE_1);
*PointerPte = TempPte;
VirtAddr = (ULONG_PTR)PointerPte << 10;
__invlpg((PVOID)VirtAddr);
KeInvalidateTlbEntry((PVOID)VirtAddr);
}
TempPte.u.Hard.PageFrameNumber = PhysAddr >> PAGE_SHIFT;
PointerPte = MiAddressToPte(MI_KDBG_TMP_PAGE_0);
*PointerPte = TempPte;
VirtAddr = (ULONG_PTR)PointerPte << 10;
__invlpg((PVOID)VirtAddr);
KeInvalidateTlbEntry((PVOID)VirtAddr);
return VirtAddr + (PhysAddr & (PAGE_SIZE - 1));
}

View File

@ -500,10 +500,10 @@ KdpReadPhysicalmemory(IN PDBGKD_MANIPULATE_STATE64 State,
/* Uncached */
Flags |= MMDBG_COPY_UNCACHED;
}
else if (CacheFlags == DBGKD_CACHING_UNCACHED)
else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
{
/* Write Combined */
Flags |= DBGKD_CACHING_WRITE_COMBINED;
Flags |= MMDBG_COPY_WRITE_COMBINED;
}
/* Do the read */
@ -553,10 +553,10 @@ KdpWritePhysicalmemory(IN PDBGKD_MANIPULATE_STATE64 State,
/* Uncached */
Flags |= MMDBG_COPY_UNCACHED;
}
else if (CacheFlags == DBGKD_CACHING_UNCACHED)
else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
{
/* Write Combined */
Flags |= DBGKD_CACHING_WRITE_COMBINED;
Flags |= MMDBG_COPY_WRITE_COMBINED;
}
/* Do the write */

View File

@ -28,6 +28,7 @@
#define MI_PAGED_POOL_START (PVOID)0xE1000000
#define MI_NONPAGED_POOL_END (PVOID)0xFFBE0000
#define MI_DEBUG_MAPPING (PVOID)0xFFBFF000
#define MM_HIGHEST_VAD_ADDRESS \
(PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))

View File

@ -62,6 +62,32 @@ MmSetAddressRangeModified(IN PVOID Address,
return FALSE;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
MmIsAddressValid(IN PVOID VirtualAddress)
{
//
// Just check the Valid bit in the Address' PDE and PTE
//
if ((MiAddressToPde(VirtualAddress)->u.Hard.Valid == 0) ||
(MiAddressToPte(VirtualAddress)->u.Hard.Valid == 0))
{
//
// Attempting to access this page is guranteed to result in a page fault
//
return FALSE;
}
//
// This address is valid now, but it will only stay so if the caller holds
// the PFN lock
//
return TRUE;
}
/*
* @unimplemented
*/

View File

@ -6,13 +6,124 @@
* PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
*/
/* INCLUDES ******************************************************************/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#include "ARM3/miarm.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
/* GLOBALS ********************************************************************/
PMMPTE MmDebugPte = MiAddressToPte(MI_DEBUG_MAPPING);
BOOLEAN MiDbgReadyForPhysical = FALSE;
/* FUNCTIONS ******************************************************************/
PVOID
NTAPI
MiDbgTranslatePhysicalAddress(IN ULONG64 PhysicalAddress,
IN ULONG Flags)
{
PFN_NUMBER Pfn;
MMPTE TempPte;
PVOID MappingBaseAddress;
//
// Check if we are called too early
//
if (MiDbgReadyForPhysical == FALSE)
{
//
// The structures we require aren't initialized yet, fail
//
KdpDprintf("MiDbgTranslatePhysicalAddress called too early! "
"Address: 0x%I64x\n", PhysicalAddress);
return NULL;
}
//
// FIXME: No support for cache flags yet
//
if ((Flags & (MMDBG_COPY_CACHED |
MMDBG_COPY_UNCACHED |
MMDBG_COPY_WRITE_COMBINED)) != 0)
{
//
// Fail
//
KdpDprintf("MiDbgTranslatePhysicalAddress: Cache Flags not yet supported. "
"Flags: 0x%lx\n", Flags & (MMDBG_COPY_CACHED |
MMDBG_COPY_UNCACHED |
MMDBG_COPY_WRITE_COMBINED));
return NULL;
}
//
// Save the base address of our mapping page
//
MappingBaseAddress = MiPteToAddress(MmDebugPte);
//
//
//
TempPte = HyperTemplatePte;
//
// Convert physical address to PFN
//
Pfn = (PFN_NUMBER)(PhysicalAddress >> PAGE_SHIFT);
//
// Check if this could be an I/O mapping
//
if (Pfn > MmHighestPhysicalPage)
{
//
// FIXME: We don't support this yet
//
KdpDprintf("MiDbgTranslatePhysicalAddress: I/O Space not yet supported. "
"PFN: 0x%I64x\n", (ULONG64)Pfn);
return NULL;
}
else
{
//
// Set the PFN in the PTE
//
TempPte.u.Hard.PageFrameNumber = Pfn;
}
//
// Map the PTE and invalidate its TLB entry
//
*MmDebugPte = TempPte;
KeInvalidateTlbEntry(MappingBaseAddress);
//
// Calculate and return the virtual offset into our mapping page
//
return (PVOID)((ULONG_PTR)MappingBaseAddress +
BYTE_OFFSET(PhysicalAddress));
}
VOID
NTAPI
MiDbgUnTranslatePhysicalAddress(VOID)
{
PVOID MappingBaseAddress = MiPteToAddress(MmDebugPte);
//
// The address must still be valid at this point
//
ASSERT(MmIsAddressValid(MappingBaseAddress));
//
// Clear the mapping PTE and invalidate its TLB entry
//
MmDebugPte->u.Long = 0;
KeInvalidateTlbEntry(MappingBaseAddress);
}
NTSTATUS
NTAPI
@ -22,87 +133,174 @@ MmDbgCopyMemory(IN ULONG64 Address,
IN ULONG Flags)
{
NTSTATUS Status;
PVOID TargetAddress;
/* For now, this must be a "unsafe" copy */
//
// No local kernel debugging support yet, so don't worry about locking
//
ASSERT(Flags & MMDBG_COPY_UNSAFE);
/* We only handle 1, 2, 4 and 8 byte requests */
//
// We only handle 1, 2, 4 and 8 byte requests
//
if ((Size != 1) &&
(Size != 2) &&
(Size != 4) &&
(Size != MMDBG_COPY_MAX_SIZE))
{
/* Invalid size, fail */
//
// Invalid size, fail
//
KdpDprintf("MmDbgCopyMemory: Received Illegal Size 0x%lx\n", Size);
return STATUS_INVALID_PARAMETER_3;
}
/* The copy must be aligned too */
//
// The copy must be aligned
//
if ((Address & (Size - 1)) != 0)
{
/* Fail */
//
// Fail
//
KdpDprintf("MmDbgCopyMemory: Received Unaligned Address 0x%I64x Size %lx\n",
Address, Size);
return STATUS_INVALID_PARAMETER_3;
}
/* No physical memory support yet */
//
// Check if this is physical or virtual copy
//
if (Flags & MMDBG_COPY_PHYSICAL)
{
/* Fail */
KdpDprintf("MmDbgCopyMemory: Failing %s for Physical Address 0x%I64x\n",
Flags & MMDBG_COPY_WRITE ? "write" : "read",
Address);
return STATUS_UNSUCCESSFUL;
}
//
// Physical: translate and map it to our mapping space
//
TargetAddress = MiDbgTranslatePhysicalAddress(Address, Flags);
/* Simple check for invalid address */
if ((MiAddressToPde((ULONG_PTR)Address)->u.Hard.Valid == 0) ||
(MiAddressToPte((ULONG_PTR)Address)->u.Hard.Valid == 0))
//
// Check if translation failed
//
if (!TargetAddress)
{
//
// Fail
//
KdpDprintf("MmDbgCopyMemory: Failed to Translate Physical Address "
"%I64x\n", Address);
return STATUS_UNSUCCESSFUL;
}
//
// The address we received must be valid!
//
ASSERT(MmIsAddressValid(TargetAddress));
}
else
{
/* Fail */
KdpDprintf("MmDbgCopyMemory: Failing %s for invalid Address 0x%p\n",
Flags & MMDBG_COPY_WRITE ? "write" : "read",
(PVOID)(ULONG_PTR)Address);
return STATUS_UNSUCCESSFUL;
//
// Virtual; truncate it to avoid casts later down
//
TargetAddress = (PVOID)(ULONG_PTR)Address;
//
// Check if the address is invalid
//
if (!MmIsAddressValid(TargetAddress))
{
//
// Fail
//
KdpDprintf("MmDbgCopyMemory: Failing %s for invalid "
"Virtual Address 0x%p\n",
Flags & MMDBG_COPY_WRITE ? "write" : "read",
TargetAddress);
return STATUS_UNSUCCESSFUL;
}
}
/* If we are going to write to it then make sure it is writeable too */
//
// If we are going to write to the address then make sure it is writeable too
//
if ((Flags & MMDBG_COPY_WRITE) &&
(!MI_IS_PAGE_WRITEABLE(MiAddressToPte((ULONG_PTR)Address))))
(!MI_IS_PAGE_WRITEABLE(MiAddressToPte(TargetAddress))))
{
/* Fail */
KdpDprintf("MmDbgCopyMemory: Failing write for Address 0x%p\n",
(PVOID)(ULONG_PTR)Address);
//
// Check if we mapped anything
//
if (Flags & MMDBG_COPY_PHYSICAL)
{
//
// Get rid of the mapping
//
MiDbgUnTranslatePhysicalAddress();
}
//
// Fail
//
// FIXME: We should attempt to override the write protection instead of
// failing here
//
KdpDprintf("MmDbgCopyMemory: Failing Write for Protected Address 0x%p\n",
TargetAddress);
return STATUS_UNSUCCESSFUL;
}
/* Use SEH to try to catch anything else somewhat cleanly */
//
// Use SEH to try to catch anything else somewhat cleanly
//
_SEH2_TRY
{
/* Check if this is read or write */
//
// Check if this is read or write
//
if (Flags & MMDBG_COPY_WRITE)
{
/* Do the write */
RtlCopyMemory((PVOID)(ULONG_PTR)Address,
//
// Do the write
//
RtlCopyMemory(TargetAddress,
Buffer,
Size);
}
else
{
/* Do the read */
//
// Do the read
//
RtlCopyMemory(Buffer,
(PVOID)(ULONG_PTR)Address,
TargetAddress,
Size);
}
/* Copy succeeded */
//
// Copy succeeded
//
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Get the exception code */
//
// Get the exception code
//
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Return status */
//
// Get rid of the mapping if this was a physical copy
//
if (Flags & MMDBG_COPY_PHYSICAL)
{
//
// Unmap and flush it
//
MiDbgUnTranslatePhysicalAddress();
}
//
// Return status to caller
//
return Status;
}

View File

@ -328,41 +328,3 @@ MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
}
return(Status);
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
*/
BOOLEAN
NTAPI
MmIsAddressValid(IN PVOID VirtualAddress)
{
MEMORY_AREA* MemoryArea;
PMMSUPPORT AddressSpace;
DPRINT1("WARNING: %s returns bogus result\n", __FUNCTION__);
if (VirtualAddress >= MmSystemRangeStart)
{
AddressSpace = MmGetKernelAddressSpace();
}
else
{
AddressSpace = &PsGetCurrentProcess()->Vm;
}
MmLockAddressSpace(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
VirtualAddress);
if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
{
MmUnlockAddressSpace(AddressSpace);
return(FALSE);
}
MmUnlockAddressSpace(AddressSpace);
return(TRUE);
}
/* EOF */

View File

@ -203,43 +203,78 @@ MiInitSystemMemoryAreas()
// And now, ReactOS paged pool
//
BaseAddress = MmPagedPoolBase;
MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_PAGED_POOL | MEMORY_AREA_STATIC,
&BaseAddress,
MmPagedPoolSize,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_PAGED_POOL | MEMORY_AREA_STATIC,
&BaseAddress,
MmPagedPoolSize,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
ASSERT(Status == STATUS_SUCCESS);
//
// Next, the KPCR
//
BaseAddress = (PVOID)PCR;
MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&BaseAddress,
PAGE_SIZE * KeNumberProcessors,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&BaseAddress,
PAGE_SIZE * KeNumberProcessors,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
ASSERT(Status == STATUS_SUCCESS);
//
// Now the KUSER_SHARED_DATA
//
BaseAddress = (PVOID)KI_USER_SHARED_DATA;
MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&BaseAddress,
PAGE_SIZE,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&BaseAddress,
PAGE_SIZE,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
ASSERT(Status == STATUS_SUCCESS);
//
// And the debugger mapping
//
BaseAddress = MI_DEBUG_MAPPING;
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&BaseAddress,
PAGE_SIZE,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
ASSERT(Status == STATUS_SUCCESS);
#if defined(_X86_)
//
// Finally, reserve the 2 pages we currently make use of for HAL mappings
//
BaseAddress = (PVOID)0xFFC00000;
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
&BaseAddress,
PAGE_SIZE * 2,
PAGE_READWRITE,
&MArea,
TRUE,
0,
BoundaryAddressMultiple);
ASSERT(Status == STATUS_SUCCESS);
#endif
}
VOID
@ -347,6 +382,12 @@ MmInitSystem(IN ULONG Phase,
// Initialize ARM³ in phase 1
//
MmArmInitSystem(1, KeLoaderBlock);
//
// Everything required for the debugger to read and write
// physical memory is now set up
//
MiDbgReadyForPhysical = TRUE;
/* Put the paged pool after the loaded modules */
MmPagedPoolBase = (PVOID)PAGE_ROUND_UP((ULONG_PTR)MmSystemRangeStart +