diff --git a/reactos/ntoskrnl/include/internal/arm/intrin_i.h b/reactos/ntoskrnl/include/internal/arm/intrin_i.h index 33d3db00681..286a1f6a355 100644 --- a/reactos/ntoskrnl/include/internal/arm/intrin_i.h +++ b/reactos/ntoskrnl/include/internal/arm/intrin_i.h @@ -3,7 +3,7 @@ FORCEINLINE VOID -KeArmHaltProcessor(void) +KeArmHaltProcessor(VOID) { // // Enter Wait-For-Interrupt Mode diff --git a/reactos/ntoskrnl/include/internal/arm/ke.h b/reactos/ntoskrnl/include/internal/arm/ke.h index 0ccc19527d3..f539cf4facb 100644 --- a/reactos/ntoskrnl/include/internal/arm/ke.h +++ b/reactos/ntoskrnl/include/internal/arm/ke.h @@ -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 diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index c40b259dcd5..f62add28422 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -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( diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 6c31ac228d3..8a8f6b7260a 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -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) diff --git a/reactos/ntoskrnl/kd/i386/kdmemsup.c b/reactos/ntoskrnl/kd/i386/kdmemsup.c index ec0f7f0f83d..3f14bcdc9c3 100644 --- a/reactos/ntoskrnl/kd/i386/kdmemsup.c +++ b/reactos/ntoskrnl/kd/i386/kdmemsup.c @@ -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)); } diff --git a/reactos/ntoskrnl/kd64/kdapi.c b/reactos/ntoskrnl/kd64/kdapi.c index 1eac9cf6dbd..43a8e375788 100644 --- a/reactos/ntoskrnl/kd64/kdapi.c +++ b/reactos/ntoskrnl/kd64/kdapi.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index 9051252b3a2..e319eee432a 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -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)) diff --git a/reactos/ntoskrnl/mm/ARM3/mmsup.c b/reactos/ntoskrnl/mm/ARM3/mmsup.c index ed73cdd9e56..6fc28279a2e 100644 --- a/reactos/ntoskrnl/mm/ARM3/mmsup.c +++ b/reactos/ntoskrnl/mm/ARM3/mmsup.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/mmdbg.c b/reactos/ntoskrnl/mm/mmdbg.c index bf846ca84aa..8224b5b739b 100644 --- a/reactos/ntoskrnl/mm/mmdbg.c +++ b/reactos/ntoskrnl/mm/mmdbg.c @@ -6,13 +6,124 @@ * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org) */ -/* INCLUDES ******************************************************************/ +/* INCLUDES *******************************************************************/ #include +#include "ARM3/miarm.h" #define NDEBUG #include -/* 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; } diff --git a/reactos/ntoskrnl/mm/mmfault.c b/reactos/ntoskrnl/mm/mmfault.c index 02b3463e4f9..15499870af7 100644 --- a/reactos/ntoskrnl/mm/mmfault.c +++ b/reactos/ntoskrnl/mm/mmfault.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index ff8a740dac2..b6607cba9e0 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -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 +