From 19d8b45f326f5ad1307ee939b6681e85301e3e07 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 14 Aug 2018 19:03:17 -0300 Subject: [PATCH] Check if memory region is contiguous --- .../Exceptions/VmmOutOfMemoryException.cs | 8 +- ChocolArm64/Memory/AMemory.cs | 486 +++++++++--------- .../OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs | 4 - 3 files changed, 247 insertions(+), 251 deletions(-) diff --git a/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs b/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs index c11384dae8..4a03b65cb9 100644 --- a/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs +++ b/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs @@ -2,12 +2,12 @@ using System; namespace ChocolArm64.Exceptions { - public class VmmOutOfMemoryException : Exception + public class VmmAccessException : Exception { - private const string ExMsg = "Failed to allocate {0} bytes of memory!"; + private const string ExMsg = "Memory region at 0x{0} with size 0x{1} is not contiguous!"; - public VmmOutOfMemoryException() { } + public VmmAccessException() { } - public VmmOutOfMemoryException(long Size) : base(string.Format(ExMsg, Size)) { } + public VmmAccessException(long Position, long Size) : base(string.Format(ExMsg, Position, Size)) { } } } \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index 341e6e3e38..676dae0b49 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -69,242 +69,6 @@ namespace ChocolArm64.Memory ObservedPages = new ConcurrentDictionary(); } - public void Map(long VA, long PA, long Size) - { - SetPTEntries(VA, RamPtr + PA, Size); - } - - public void Unmap(long Position, long Size) - { - SetPTEntries(Position, null, Size); - - StopObservingRegion(Position, Size); - } - - public bool IsMapped(long Position) - { - if (!(IsValidPosition(Position))) - { - return false; - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return false; - } - - return PageTable[L0][L1] != null || ObservedPages.ContainsKey(Position >> PTPageBits); - } - - public long GetPhysicalAddress(long VirtualAddress) - { - byte* Ptr = Translate(VirtualAddress); - - return (long)(Ptr - RamPtr); - } - - internal byte* Translate(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - byte** Lvl1 = PageTable[L0]; - - if (Lvl1 == null) - { - return HandleNullPte(Position); - } - - long Old = Position; - - Position &= PageMask; - - byte* Ptr = Lvl1[L1]; - - if (Ptr == null) - { - return HandleNullPte(Old); - } - - return Ptr + Position; - } - - private byte* HandleNullPte(long Position) - { - long Key = Position >> PTPageBits; - - if (ObservedPages.TryGetValue(Key, out IntPtr Ptr)) - { - return (byte*)Ptr + (Position & PageMask); - } - - throw new VmmPageFaultException(Position); - } - - internal byte* TranslateWrite(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - byte** Lvl1 = PageTable[L0]; - - if (Lvl1 == null) - { - return HandleNullPteWrite(Position); - } - - long Old = Position; - - Position &= PageMask; - - byte* Ptr = Lvl1[L1]; - - if (Ptr == null) - { - return HandleNullPteWrite(Old); - } - - return Ptr + Position; - } - - private byte* HandleNullPteWrite(long Position) - { - long Key = Position >> PTPageBits; - - if (ObservedPages.TryGetValue(Key, out IntPtr Ptr)) - { - SetPTEntry(Position, (byte*)Ptr); - - return (byte*)Ptr + (Position & PageMask); - } - - throw new VmmPageFaultException(Position); - } - - private void SetPTEntries(long VA, byte* Ptr, long Size) - { - long EndPosition = (VA + Size + PageMask) & ~PageMask; - - while ((ulong)VA < (ulong)EndPosition) - { - SetPTEntry(VA, Ptr); - - VA += PageSize; - - if (Ptr != null) - { - Ptr += PageSize; - } - } - } - - private void SetPTEntry(long Position, byte* Ptr) - { - if (!IsValidPosition(Position)) - { - throw new ArgumentOutOfRangeException(nameof(Position)); - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - byte** Lvl1 = (byte**)Marshal.AllocHGlobal(PTLvl1Size * IntPtr.Size); - - for (int ZL1 = 0; ZL1 < PTLvl1Size; ZL1++) - { - Lvl1[ZL1] = null; - } - - Thread.MemoryBarrier(); - - PageTable[L0] = Lvl1; - } - - PageTable[L0][L1] = Ptr; - } - - public (bool[], int) IsRegionModified(long Position, long Size) - { - long EndPosition = (Position + Size + PageMask) & ~PageMask; - - Position &= ~PageMask; - - Size = EndPosition - Position; - - bool[] Modified = new bool[Size >> PTPageBits]; - - int Count = 0; - - lock (ObservedPages) - { - for (int Page = 0; Page < Modified.Length; Page++) - { - byte* Ptr = Translate(Position); - - if (ObservedPages.TryAdd(Position >> PTPageBits, (IntPtr)Ptr)) - { - Modified[Page] = true; - } - else - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - byte** Lvl1 = PageTable[L0]; - - if (Lvl1 != null) - { - if (Modified[Page] = Lvl1[L1] != null) - { - Count++; - } - } - } - - SetPTEntry(Position, null); - - Position += PageSize; - } - } - - return (Modified, Count); - } - - public void StopObservingRegion(long Position, long Size) - { - long EndPosition = (Position + Size + PageMask) & ~PageMask; - - while (Position < EndPosition) - { - lock (ObservedPages) - { - if (ObservedPages.TryRemove(Position >> PTPageBits, out IntPtr Ptr)) - { - SetPTEntry(Position, (byte*)Ptr); - } - } - - Position += PageSize; - } - } - - public IntPtr GetHostAddress(long Position, long Size) - { - EnsureRangeIsValid(Position, Size); - - return (IntPtr)Translate(Position); - } - - public bool IsValidPosition(long Position) - { - return Position >> (PTLvl0Bits + PTLvl1Bits + PTPageBits) == 0; - } - public void RemoveMonitor(AThreadState State) { lock (Monitors) @@ -639,26 +403,262 @@ namespace ChocolArm64.Memory Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length); } + public void Map(long VA, long PA, long Size) + { + SetPTEntries(VA, RamPtr + PA, Size); + } + + public void Unmap(long Position, long Size) + { + SetPTEntries(Position, null, Size); + + StopObservingRegion(Position, Size); + } + + public bool IsMapped(long Position) + { + if (!(IsValidPosition(Position))) + { + return false; + } + + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return false; + } + + return PageTable[L0][L1] != null || ObservedPages.ContainsKey(Position >> PTPageBits); + } + + public long GetPhysicalAddress(long VirtualAddress) + { + byte* Ptr = Translate(VirtualAddress); + + return (long)(Ptr - RamPtr); + } + + internal byte* Translate(long Position) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + byte** Lvl1 = PageTable[L0]; + + if (Lvl1 == null) + { + return HandleNullPte(Position); + } + + long Old = Position; + + Position &= PageMask; + + byte* Ptr = Lvl1[L1]; + + if (Ptr == null) + { + return HandleNullPte(Old); + } + + return Ptr + Position; + } + + private byte* HandleNullPte(long Position) + { + long Key = Position >> PTPageBits; + + if (ObservedPages.TryGetValue(Key, out IntPtr Ptr)) + { + return (byte*)Ptr + (Position & PageMask); + } + + throw new VmmPageFaultException(Position); + } + + internal byte* TranslateWrite(long Position) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + byte** Lvl1 = PageTable[L0]; + + if (Lvl1 == null) + { + return HandleNullPteWrite(Position); + } + + long Old = Position; + + Position &= PageMask; + + byte* Ptr = Lvl1[L1]; + + if (Ptr == null) + { + return HandleNullPteWrite(Old); + } + + return Ptr + Position; + } + + private byte* HandleNullPteWrite(long Position) + { + long Key = Position >> PTPageBits; + + if (ObservedPages.TryGetValue(Key, out IntPtr Ptr)) + { + SetPTEntry(Position, (byte*)Ptr); + + return (byte*)Ptr + (Position & PageMask); + } + + throw new VmmPageFaultException(Position); + } + + private void SetPTEntries(long VA, byte* Ptr, long Size) + { + long EndPosition = (VA + Size + PageMask) & ~PageMask; + + while ((ulong)VA < (ulong)EndPosition) + { + SetPTEntry(VA, Ptr); + + VA += PageSize; + + if (Ptr != null) + { + Ptr += PageSize; + } + } + } + + private void SetPTEntry(long Position, byte* Ptr) + { + if (!IsValidPosition(Position)) + { + throw new ArgumentOutOfRangeException(nameof(Position)); + } + + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + byte** Lvl1 = (byte**)Marshal.AllocHGlobal(PTLvl1Size * IntPtr.Size); + + for (int ZL1 = 0; ZL1 < PTLvl1Size; ZL1++) + { + Lvl1[ZL1] = null; + } + + Thread.MemoryBarrier(); + + PageTable[L0] = Lvl1; + } + + PageTable[L0][L1] = Ptr; + } + + public (bool[], int) IsRegionModified(long Position, long Size) + { + long EndPosition = (Position + Size + PageMask) & ~PageMask; + + Position &= ~PageMask; + + Size = EndPosition - Position; + + bool[] Modified = new bool[Size >> PTPageBits]; + + int Count = 0; + + lock (ObservedPages) + { + for (int Page = 0; Page < Modified.Length; Page++) + { + byte* Ptr = Translate(Position); + + if (ObservedPages.TryAdd(Position >> PTPageBits, (IntPtr)Ptr)) + { + Modified[Page] = true; + } + else + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + byte** Lvl1 = PageTable[L0]; + + if (Lvl1 != null) + { + if (Modified[Page] = Lvl1[L1] != null) + { + Count++; + } + } + } + + SetPTEntry(Position, null); + + Position += PageSize; + } + } + + return (Modified, Count); + } + + public void StopObservingRegion(long Position, long Size) + { + long EndPosition = (Position + Size + PageMask) & ~PageMask; + + while (Position < EndPosition) + { + lock (ObservedPages) + { + if (ObservedPages.TryRemove(Position >> PTPageBits, out IntPtr Ptr)) + { + SetPTEntry(Position, (byte*)Ptr); + } + } + + Position += PageSize; + } + } + + public IntPtr GetHostAddress(long Position, long Size) + { + EnsureRangeIsValid(Position, Size); + + return (IntPtr)Translate(Position); + } + internal void EnsureRangeIsValid(long Position, long Size) { long EndPos = Position + Size; Position &= ~PageMask; + long ExpectedPA = GetPhysicalAddress(Position); + while ((ulong)Position < (ulong)EndPos) { - EnsureAccessIsValid(Position); + long PA = GetPhysicalAddress(Position); - Position += PageSize; + if (PA != ExpectedPA) + { + throw new VmmAccessException(Position, Size); + } + + Position += PageSize; + ExpectedPA += PageSize; } } - private void EnsureAccessIsValid(long Position) + public bool IsValidPosition(long Position) { - if (!IsMapped(Position)) - { - throw new VmmPageFaultException(Position); - } + return Position >> (PTLvl0Bits + PTLvl1Bits + PTPageBits) == 0; } public void Dispose() diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs index 262f3c35d8..3c67cef09b 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs @@ -59,8 +59,6 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS ulong Size = (ulong)Args.Pages * (ulong)Args.PageSize; - long oldoffs = Args.Offset; - int Result = NvResult.Success; lock (ASCtx) @@ -174,8 +172,6 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS return NvResult.InvalidInput; } - long oldoffs = Args.Offset; - long PA; if ((Args.Flags & FlagRemapSubRange) != 0)