diff --git a/src/CxbxKrnl/EmuKrnlMm.cpp b/src/CxbxKrnl/EmuKrnlMm.cpp index c4c7b573c..b8c211fd0 100644 --- a/src/CxbxKrnl/EmuKrnlMm.cpp +++ b/src/CxbxKrnl/EmuKrnlMm.cpp @@ -52,6 +52,7 @@ namespace xboxkrnl #include "Emu.h" // For EmuWarning() #include "VMManager.h" #include "EmuShared.h" +#include // prevent name collisions namespace NtDll @@ -462,14 +463,7 @@ XBSYSAPI EXPORTNUM(181) xboxkrnl::NTSTATUS NTAPI xboxkrnl::MmQueryStatistics NTSTATUS ret; -#ifdef _DEBUG_TRACE - if (!MemoryStatistics) - { - DbgPrintf("KNRL: MmQueryStatistics : PMM_STATISTICS MemoryStatistics is nullptr!\n"); - LOG_IGNORED(); - RETURN(STATUS_SUCCESS); - } -#endif + assert(MemoryStatistics); if (MemoryStatistics->Length == sizeof(MM_STATISTICS)) { @@ -549,9 +543,13 @@ XBSYSAPI EXPORTNUM(374) xboxkrnl::PVOID NTAPI xboxkrnl::MmDbgAllocateMemory LOG_FUNC_ARG(Protect) LOG_FUNC_END; - LOG_UNIMPLEMENTED(); + // This should only be called by debug xbe's + assert(g_bIsDebug); - RETURN(NULL); + PVOID addr = (PVOID)g_VMManager.AllocateSystemMemory(PageType::Debugger, Protect, NumberOfBytes, false); + if (addr) { FillMemoryUlong((void*)addr, ROUND_UP_4K(NumberOfBytes), 0); } // debugger pages are zeroed + + RETURN(addr); } // ****************************************************************** @@ -568,9 +566,12 @@ XBSYSAPI EXPORTNUM(375) xboxkrnl::ULONG NTAPI xboxkrnl::MmDbgFreeMemory LOG_FUNC_ARG(NumberOfBytes) LOG_FUNC_END; - LOG_UNIMPLEMENTED(); + // This should only be called by debug xbe's + assert(g_bIsDebug); - RETURN(NULL); + ULONG FreedPagesNumber = g_VMManager.DeallocateSystemMemory(PageType::Debugger, (VAddr)BaseAddress, NumberOfBytes); + + RETURN(FreedPagesNumber); } // ****************************************************************** diff --git a/src/CxbxKrnl/VMManager.cpp b/src/CxbxKrnl/VMManager.cpp index 73eed734e..bc7ae6d9c 100644 --- a/src/CxbxKrnl/VMManager.cpp +++ b/src/CxbxKrnl/VMManager.cpp @@ -446,13 +446,12 @@ VAddr VMManager::AllocateZeroed(size_t Size) RETURN(addr); } -VAddr VMManager::AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Size, /*bool bDebugRange,*/ bool bAddGuardPage) +VAddr VMManager::AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Size, bool bAddGuardPage) { LOG_FUNC_BEGIN LOG_FUNC_ARG(BusyType); LOG_FUNC_ARG(Perms); LOG_FUNC_ARG(Size); - //LOG_FUNC_ARG(bDebugRange); LOG_FUNC_ARG(bAddGuardPage); LOG_FUNC_END; @@ -461,10 +460,12 @@ VAddr VMManager::AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Siz PMMPTE EndingPte; PFN pfn; PFN EndingPfn; + PFN_COUNT LowerAcceptablePfn = 0; PFN_COUNT PteNumber; VAddr addr; MappingFn MappingRoutine; bool bVAlloc = false; + MemoryRegionType MemoryType = MemoryRegionType::System; if (!Size || !ConvertXboxToSystemPteProtection(Perms, &TempPte)) { RETURN(NULL); } @@ -474,11 +475,19 @@ VAddr VMManager::AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Siz if (bAddGuardPage) { PteNumber++; Size += PAGE_SIZE; } if (!IsMappable(PteNumber)) { goto Fail; } + if (BusyType == PageType::Debugger) + { + // Debugger pages are only allocated from the extra 64 Mib available on devkits and are mapped in the + // devkit system region - if (RemoveFree(PteNumber, &pfn, 0, 0, m_HighestPage)) // MapViewOfFileEx path + LowerAcceptablePfn = DEBUGKIT_FIRST_UPPER_HALF_PAGE; + MemoryType = MemoryRegionType::Devkit; + } + + if (RemoveFree(PteNumber, &pfn, 0, LowerAcceptablePfn, m_HighestPage)) // MapViewOfFileEx path { MappingRoutine = &MapBlockWithMapViewOfFileEx; - addr = MapMemoryBlock(MappingRoutine, MemoryRegionType::System, PteNumber, pfn); + addr = MapMemoryBlock(MappingRoutine, MemoryType, PteNumber, pfn); if (!addr) { @@ -495,7 +504,7 @@ VAddr VMManager::AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Siz bVAlloc = true; MappingRoutine = &MapBlockWithVirtualAlloc; - addr = MapMemoryBlock(MappingRoutine, MemoryRegionType::System, PteNumber, 0); + addr = MapMemoryBlock(MappingRoutine, MemoryType, PteNumber, 0); if (!addr) { goto Fail; } @@ -555,7 +564,7 @@ VAddr VMManager::AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Siz m_PagesByUsage[BusyType] += PteNumber; } - ConstructVMA(addr, PteNumber << PAGE_SHIFT, MemoryRegionType::System, VMAType::Allocated, bVAlloc); + ConstructVMA(addr, PteNumber << PAGE_SHIFT, MemoryType, VMAType::Allocated, bVAlloc); if (bAddGuardPage) { @@ -801,7 +810,7 @@ void VMManager::DeallocateContiguous(VAddr addr) Unlock(); } -PFN_COUNT VMManager::DeallocateSystemMemory(PageType BusyType, VAddr addr, size_t Size /*MemoryRegionType Type*/) +PFN_COUNT VMManager::DeallocateSystemMemory(PageType BusyType, VAddr addr, size_t Size) { LOG_FUNC_BEGIN LOG_FUNC_ARG(addr); @@ -815,21 +824,41 @@ PFN_COUNT VMManager::DeallocateSystemMemory(PageType BusyType, VAddr addr, size_ PFN EndingPfn; PFN_COUNT PteNumber; VMAIter it; + MemoryRegionType MemoryType = MemoryRegionType::System; assert(CHECK_ALIGNMENT(addr, PAGE_SIZE)); // all starting addresses in the system region are page aligned Lock(); - it = CheckExistenceVMA(addr, MemoryRegionType::System, ROUND_UP_4K(Size)); + if (BusyType == PageType::Debugger) + { + // ergo720: I'm not sure but MmDbgFreeMemory seems to be able to deallocate only a part of an allocation done by + // MmDbgAllocateMemory. This is not a problem since CarveVMARange supports freeing only a part of an allocated + // vma, but we won't pass its size to CheckExistenceVMA because it would fail the size check - if (it == m_MemoryRegionArray[MemoryRegionType::System].RegionMap.end() || it->second.type == VMAType::Free) + MemoryType = MemoryRegionType::Devkit; + it = CheckExistenceVMA(addr, MemoryType); + } + else + { + it = CheckExistenceVMA(addr, MemoryType, ROUND_UP_4K(Size)); + } + + if (it == m_MemoryRegionArray[MemoryType].RegionMap.end() || it->second.type == VMAType::Free) { Unlock(); RETURN(NULL); } StartingPte = GetPteAddress(addr); - EndingPte = StartingPte + (it->second.size >> PAGE_SHIFT) - 1; + if (BusyType == PageType::Debugger) + { + EndingPte = StartingPte + (ROUND_UP_4K(Size) >> PAGE_SHIFT) - 1; + } + else + { + EndingPte = StartingPte + (it->second.size >> PAGE_SHIFT) - 1; + } pfn = StartingPte->Hardware.PFN; EndingPfn = pfn + (EndingPte - StartingPte); @@ -848,7 +877,7 @@ PFN_COUNT VMManager::DeallocateSystemMemory(PageType BusyType, VAddr addr, size_ } WritePte(StartingPte, EndingPte, TempPte, 0, true); - DestructVMA(it, MemoryRegionType::System); + DestructVMA(it, MemoryType); Unlock(); RETURN(PteNumber); @@ -871,7 +900,8 @@ void VMManager::UnmapDeviceMemory(VAddr addr, size_t Size) PFN_COUNT PteNumber; VMAIter it; - assert(CHECK_ALIGNMENT(addr, PAGE_SIZE)); // all starting addresses in the system region are page aligned + // The starting address of a device can be unaligned since MapDeviceMemory returns an offset from the aligned + // mapped address, so we won't assert the address here Lock(); diff --git a/src/CxbxKrnl/VMManager.h b/src/CxbxKrnl/VMManager.h index 8e727cacf..b6bf8f076 100644 --- a/src/CxbxKrnl/VMManager.h +++ b/src/CxbxKrnl/VMManager.h @@ -132,13 +132,13 @@ class VMManager : public PhysicalMemory // allocates memory in the user region and zeros it VAddr AllocateZeroed(size_t size); // allocates memory in the system region - VAddr AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Size, /*bool bDebugRange,*/ bool bAddGuardPage); + VAddr AllocateSystemMemory(PageType BusyType, DWORD Perms, size_t Size, bool bAddGuardPage); // allocates memory in the contiguous region VAddr AllocateContiguous(size_t Size, PAddr LowerAddress, PAddr HigherAddress, ULONG Alignment, DWORD Perms); // maps device memory in the system region VAddr MapDeviceMemory(PAddr Paddr, size_t Size, DWORD Perms); // deallocates memory in the system region - PFN_COUNT DeallocateSystemMemory(PageType BusyType, VAddr addr, size_t Size /*MemoryRegionType Type*/); + PFN_COUNT DeallocateSystemMemory(PageType BusyType, VAddr addr, size_t Size); // deallocates memory in the contiguous region void DeallocateContiguous(VAddr addr); // unmaps device memory in the system region