diff --git a/ChocolArm64/AOptimizations.cs b/ChocolArm64/AOptimizations.cs index 800cf363d7..fbf26a4910 100644 --- a/ChocolArm64/AOptimizations.cs +++ b/ChocolArm64/AOptimizations.cs @@ -2,8 +2,6 @@ using System.Runtime.Intrinsics.X86; public static class AOptimizations { - public static bool DisableMemoryChecks = false; - public static bool GenerateCallStack = true; private static bool UseAllSseIfAvailable = true; diff --git a/ChocolArm64/Exceptions/VmmAccessViolationException.cs b/ChocolArm64/Exceptions/VmmAccessViolationException.cs deleted file mode 100644 index a557502e50..0000000000 --- a/ChocolArm64/Exceptions/VmmAccessViolationException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ChocolArm64.Memory; -using System; - -namespace ChocolArm64.Exceptions -{ - public class VmmAccessViolationException : Exception - { - private const string ExMsg = "Address 0x{0:x16} does not have \"{1}\" permission!"; - - public VmmAccessViolationException() { } - - public VmmAccessViolationException(long Position, AMemoryPerm Perm) : base(string.Format(ExMsg, Position, Perm)) { } - } -} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs b/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs index df091bd514..b10551fe07 100644 --- a/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs @@ -45,46 +45,21 @@ namespace ChocolArm64.Instruction { switch (Size) { - case 0: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadVector8Unchecked) - : nameof(AMemory.ReadVector8); break; - - case 1: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadVector16Unchecked) - : nameof(AMemory.ReadVector16); break; - - case 2: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadVector32Unchecked) - : nameof(AMemory.ReadVector32); break; - - case 3: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadVector64Unchecked) - : nameof(AMemory.ReadVector64); break; - - case 4: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadVector128Unchecked) - : nameof(AMemory.ReadVector128); break; + case 0: Name = nameof(AMemory.ReadVector8); break; + case 1: Name = nameof(AMemory.ReadVector16); break; + case 2: Name = nameof(AMemory.ReadVector32); break; + case 3: Name = nameof(AMemory.ReadVector64); break; + case 4: Name = nameof(AMemory.ReadVector128); break; } } else { switch (Size) { - case 0: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadByteUnchecked) - : nameof(AMemory.ReadByte); break; - - case 1: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadUInt16Unchecked) - : nameof(AMemory.ReadUInt16); break; - - case 2: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadUInt32Unchecked) - : nameof(AMemory.ReadUInt32); break; - - case 3: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.ReadUInt64Unchecked) - : nameof(AMemory.ReadUInt64); break; + case 0: Name = nameof(AMemory.ReadByte); break; + case 1: Name = nameof(AMemory.ReadUInt16); break; + case 2: Name = nameof(AMemory.ReadUInt32); break; + case 3: Name = nameof(AMemory.ReadUInt64); break; } } @@ -132,46 +107,21 @@ namespace ChocolArm64.Instruction { switch (Size) { - case 0: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteVector8Unchecked) - : nameof(AMemory.WriteVector8); break; - - case 1: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteVector16Unchecked) - : nameof(AMemory.WriteVector16); break; - - case 2: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteVector32Unchecked) - : nameof(AMemory.WriteVector32); break; - - case 3: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteVector64Unchecked) - : nameof(AMemory.WriteVector64); break; - - case 4: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteVector128Unchecked) - : nameof(AMemory.WriteVector128); break; + case 0: Name = nameof(AMemory.WriteVector8); break; + case 1: Name = nameof(AMemory.WriteVector16); break; + case 2: Name = nameof(AMemory.WriteVector32); break; + case 3: Name = nameof(AMemory.WriteVector64); break; + case 4: Name = nameof(AMemory.WriteVector128); break; } } else { switch (Size) { - case 0: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteByteUnchecked) - : nameof(AMemory.WriteByte); break; - - case 1: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteUInt16Unchecked) - : nameof(AMemory.WriteUInt16); break; - - case 2: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteUInt32Unchecked) - : nameof(AMemory.WriteUInt32); break; - - case 3: Name = AOptimizations.DisableMemoryChecks - ? nameof(AMemory.WriteUInt64Unchecked) - : nameof(AMemory.WriteUInt64); break; + case 0: Name = nameof(AMemory.WriteByte); break; + case 1: Name = nameof(AMemory.WriteUInt16); break; + case 2: Name = nameof(AMemory.WriteUInt32); break; + case 3: Name = nameof(AMemory.WriteUInt64); break; } } diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index e969cca5fe..2ff32fcfdf 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -1,6 +1,7 @@ using ChocolArm64.Exceptions; using ChocolArm64.State; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -10,11 +11,24 @@ using System.Threading; namespace ChocolArm64.Memory { - public unsafe class AMemory : IAMemory, IDisposable + public unsafe class AMemory : IAMemory { - private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; + private const int PTLvl0Bits = 10; + private const int PTLvl1Bits = 10; + private const int PTPageBits = 12; - public AMemoryMgr Manager { get; private set; } + private const int PTLvl0Size = 1 << PTLvl0Bits; + private const int PTLvl1Size = 1 << PTLvl1Bits; + public const int PageSize = 1 << PTPageBits; + + private const int PTLvl0Mask = PTLvl0Size - 1; + private const int PTLvl1Mask = PTLvl1Size - 1; + public const int PageMask = PageSize - 1; + + private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; + private const int PTLvl1Bit = PTPageBits; + + private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; private class ArmMonitor { @@ -33,28 +47,257 @@ namespace ChocolArm64.Memory private byte* RamPtr; - private int HostPageSize; + private byte*** PageTable; - public AMemory() + private ConcurrentDictionary ObservedPages; + + public AMemory(IntPtr Ram) { - Manager = new AMemoryMgr(); - Monitors = new Dictionary(); - IntPtr Size = (IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Ram = AMemoryWin32.Allocate(Size); - - HostPageSize = AMemoryWin32.GetPageSize(Ram, Size); - } - else - { - Ram = Marshal.AllocHGlobal(Size); - } + this.Ram = Ram; RamPtr = (byte*)Ram; + + PageTable = (byte***)Marshal.AllocHGlobal(PTLvl0Size * IntPtr.Size); + + for (int L0 = 0; L0 < PTLvl0Size; L0++) + { + PageTable[L0] = null; + } + + 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); + } + + return RamPtr; + } + + 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); + } + + return RamPtr; + } + + 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[] IsRegionModified(long Position, long Size) + { + long EndPosition = (Position + Size + PageMask) & ~PageMask; + + Position &= ~PageMask; + + Size = EndPosition - Position; + + bool[] Modified = new bool[Size >> PTPageBits]; + + 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) + { + Modified[Page] = Lvl1[L1] != null; + } + } + + 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) @@ -155,62 +398,6 @@ namespace ChocolArm64.Memory } } - public int GetHostPageSize() - { - return HostPageSize; - } - - public (bool[], long) IsRegionModified(long Position, long Size) - { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return (null, 0); - } - - long EndPos = Position + Size; - - if ((ulong)EndPos < (ulong)Position) - { - return (null, 0); - } - - if ((ulong)EndPos > AMemoryMgr.RamSize) - { - return (null, 0); - } - - IntPtr MemAddress = new IntPtr(RamPtr + Position); - IntPtr MemSize = new IntPtr(Size); - - int HostPageMask = HostPageSize - 1; - - Position &= ~HostPageMask; - - Size = EndPos - Position; - - IntPtr[] Addresses = new IntPtr[(Size + HostPageMask) / HostPageSize]; - - AMemoryWin32.IsRegionModified(MemAddress, MemSize, Addresses, out int Count); - - bool[] Modified = new bool[Addresses.Length]; - - for (int Index = 0; Index < Count; Index++) - { - long VA = Addresses[Index].ToInt64() - Ram.ToInt64(); - - Modified[(VA - Position) / HostPageSize] = true; - } - - return (Modified, Count); - } - - public IntPtr GetHostAddress(long Position, long Size) - { - EnsureRangeIsValid(Position, Size, AMemoryPerm.Read); - - return (IntPtr)(RamPtr + (ulong)Position); - } - public sbyte ReadSByte(long Position) { return (sbyte)ReadByte(Position); @@ -233,33 +420,22 @@ namespace ChocolArm64.Memory public byte ReadByte(long Position) { - EnsureAccessIsValid(Position, AMemoryPerm.Read); - - return ReadByteUnchecked(Position); + return *((byte*)Translate(Position)); } public ushort ReadUInt16(long Position) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Read); - EnsureAccessIsValid(Position + 1, AMemoryPerm.Read); - - return ReadUInt16Unchecked(Position); + return *((ushort*)Translate(Position)); } public uint ReadUInt32(long Position) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Read); - EnsureAccessIsValid(Position + 3, AMemoryPerm.Read); - - return ReadUInt32Unchecked(Position); + return *((uint*)Translate(Position)); } public ulong ReadUInt64(long Position) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Read); - EnsureAccessIsValid(Position + 7, AMemoryPerm.Read); - - return ReadUInt64Unchecked(Position); + return *((ulong*)Translate(Position)); } public Vector128 ReadVector8(long Position) @@ -274,6 +450,7 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector128 ReadVector16(long Position) { if (Sse2.IsSupported) @@ -286,14 +463,12 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.NoInlining)] public Vector128 ReadVector32(long Position) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Read); - EnsureAccessIsValid(Position + 3, AMemoryPerm.Read); - if (Sse.IsSupported) { - return Sse.LoadScalarVector128((float*)(RamPtr + (uint)Position)); + return Sse.LoadScalarVector128((float*)Translate(Position)); } else { @@ -301,14 +476,12 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.NoInlining)] public Vector128 ReadVector64(long Position) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Read); - EnsureAccessIsValid(Position + 7, AMemoryPerm.Read); - if (Sse2.IsSupported) { - return Sse.StaticCast(Sse2.LoadScalarVector128((double*)(RamPtr + (uint)Position))); + return Sse.StaticCast(Sse2.LoadScalarVector128((double*)Translate(Position))); } else { @@ -316,118 +489,12 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector128 ReadVector128(long Position) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Read); - EnsureAccessIsValid(Position + 15, AMemoryPerm.Read); - if (Sse.IsSupported) { - return Sse.LoadVector128((float*)(RamPtr + (uint)Position)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public sbyte ReadSByteUnchecked(long Position) - { - return (sbyte)ReadByteUnchecked(Position); - } - - public short ReadInt16Unchecked(long Position) - { - return (short)ReadUInt16Unchecked(Position); - } - - public int ReadInt32Unchecked(long Position) - { - return (int)ReadUInt32Unchecked(Position); - } - - public long ReadInt64Unchecked(long Position) - { - return (long)ReadUInt64Unchecked(Position); - } - - public byte ReadByteUnchecked(long Position) - { - return *((byte*)(RamPtr + (uint)Position)); - } - - public ushort ReadUInt16Unchecked(long Position) - { - return *((ushort*)(RamPtr + (uint)Position)); - } - - public uint ReadUInt32Unchecked(long Position) - { - return *((uint*)(RamPtr + (uint)Position)); - } - - public ulong ReadUInt64Unchecked(long Position) - { - return *((ulong*)(RamPtr + (uint)Position)); - } - - public Vector128 ReadVector8Unchecked(long Position) - { - if (Sse2.IsSupported) - { - return Sse.StaticCast(Sse2.SetVector128(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ReadByte(Position))); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128 ReadVector16Unchecked(long Position) - { - if (Sse2.IsSupported) - { - return Sse.StaticCast(Sse2.Insert(Sse2.SetZeroVector128(), ReadUInt16Unchecked(Position), 0)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public Vector128 ReadVector32Unchecked(long Position) - { - if (Sse.IsSupported) - { - return Sse.LoadScalarVector128((float*)(RamPtr + (uint)Position)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public Vector128 ReadVector64Unchecked(long Position) - { - if (Sse2.IsSupported) - { - return Sse.StaticCast(Sse2.LoadScalarVector128((double*)(RamPtr + (uint)Position))); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128 ReadVector128Unchecked(long Position) - { - if (Sse.IsSupported) - { - return Sse.LoadVector128((float*)(RamPtr + (uint)Position)); + return Sse.LoadVector128((float*)Translate(Position)); } else { @@ -442,11 +509,11 @@ namespace ChocolArm64.Memory throw new ArgumentOutOfRangeException(nameof(Size)); } - EnsureRangeIsValid(Position, Size, AMemoryPerm.Read); + EnsureRangeIsValid(Position, Size); byte[] Data = new byte[Size]; - Marshal.Copy((IntPtr)(RamPtr + (uint)Position), Data, 0, (int)Size); + Marshal.Copy((IntPtr)Translate(Position), Data, 0, (int)Size); return Data; } @@ -473,35 +540,25 @@ namespace ChocolArm64.Memory public void WriteByte(long Position, byte Value) { - EnsureAccessIsValid(Position, AMemoryPerm.Write); - - WriteByteUnchecked(Position, Value); + *((byte*)TranslateWrite(Position)) = Value; } public void WriteUInt16(long Position, ushort Value) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Write); - EnsureAccessIsValid(Position + 1, AMemoryPerm.Write); - - WriteUInt16Unchecked(Position, Value); + *((ushort*)TranslateWrite(Position)) = Value; } public void WriteUInt32(long Position, uint Value) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Write); - EnsureAccessIsValid(Position + 3, AMemoryPerm.Write); - - WriteUInt32Unchecked(Position, Value); + *((uint*)TranslateWrite(Position)) = Value; } public void WriteUInt64(long Position, ulong Value) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Write); - EnsureAccessIsValid(Position + 7, AMemoryPerm.Write); - - WriteUInt64Unchecked(Position, Value); + *((ulong*)TranslateWrite(Position)) = Value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector8(long Position, Vector128 Value) { if (Sse41.IsSupported) @@ -518,6 +575,7 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector16(long Position, Vector128 Value) { if (Sse2.IsSupported) @@ -530,14 +588,12 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.NoInlining)] public void WriteVector32(long Position, Vector128 Value) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Write); - EnsureAccessIsValid(Position + 3, AMemoryPerm.Write); - if (Sse.IsSupported) { - Sse.StoreScalar((float*)(RamPtr + (uint)Position), Value); + Sse.StoreScalar((float*)TranslateWrite(Position), Value); } else { @@ -545,14 +601,12 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.NoInlining)] public void WriteVector64(long Position, Vector128 Value) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Write); - EnsureAccessIsValid(Position + 7, AMemoryPerm.Write); - if (Sse2.IsSupported) { - Sse2.StoreScalar((double*)(RamPtr + (uint)Position), Sse.StaticCast(Value)); + Sse2.StoreScalar((double*)TranslateWrite(Position), Sse.StaticCast(Value)); } else { @@ -560,123 +614,12 @@ namespace ChocolArm64.Memory } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector128(long Position, Vector128 Value) { - EnsureAccessIsValid(Position + 0, AMemoryPerm.Write); - EnsureAccessIsValid(Position + 15, AMemoryPerm.Write); - if (Sse.IsSupported) { - Sse.Store((float*)(RamPtr + (uint)Position), Value); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public void WriteSByteUnchecked(long Position, sbyte Value) - { - WriteByteUnchecked(Position, (byte)Value); - } - - public void WriteInt16Unchecked(long Position, short Value) - { - WriteUInt16Unchecked(Position, (ushort)Value); - } - - public void WriteInt32Unchecked(long Position, int Value) - { - WriteUInt32Unchecked(Position, (uint)Value); - } - - public void WriteInt64Unchecked(long Position, long Value) - { - WriteUInt64Unchecked(Position, (ulong)Value); - } - - public void WriteByteUnchecked(long Position, byte Value) - { - *((byte*)(RamPtr + (uint)Position)) = Value; - } - - public void WriteUInt16Unchecked(long Position, ushort Value) - { - *((ushort*)(RamPtr + (uint)Position)) = Value; - } - - public void WriteUInt32Unchecked(long Position, uint Value) - { - *((uint*)(RamPtr + (uint)Position)) = Value; - } - - public void WriteUInt64Unchecked(long Position, ulong Value) - { - *((ulong*)(RamPtr + (uint)Position)) = Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector8Unchecked(long Position, Vector128 Value) - { - if (Sse41.IsSupported) - { - WriteByteUnchecked(Position, Sse41.Extract(Sse.StaticCast(Value), 0)); - } - else if (Sse2.IsSupported) - { - WriteByteUnchecked(Position, (byte)Sse2.Extract(Sse.StaticCast(Value), 0)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector16Unchecked(long Position, Vector128 Value) - { - if (Sse2.IsSupported) - { - WriteUInt16Unchecked(Position, Sse2.Extract(Sse.StaticCast(Value), 0)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void WriteVector32Unchecked(long Position, Vector128 Value) - { - if (Sse.IsSupported) - { - Sse.StoreScalar((float*)(RamPtr + (uint)Position), Value); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public void WriteVector64Unchecked(long Position, Vector128 Value) - { - if (Sse2.IsSupported) - { - Sse2.StoreScalar((double*)(RamPtr + (uint)Position), Sse.StaticCast(Value)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector128Unchecked(long Position, Vector128 Value) - { - if (Sse.IsSupported) - { - Sse.Store((float*)(RamPtr + (uint)Position), Value); + Sse.Store((float*)TranslateWrite(Position), Value); } else { @@ -686,58 +629,31 @@ namespace ChocolArm64.Memory public void WriteBytes(long Position, byte[] Data) { - EnsureRangeIsValid(Position, (uint)Data.Length, AMemoryPerm.Write); + EnsureRangeIsValid(Position, (uint)Data.Length); - Marshal.Copy(Data, 0, (IntPtr)(RamPtr + (uint)Position), Data.Length); + Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length); } - private void EnsureRangeIsValid(long Position, long Size, AMemoryPerm Perm) + internal void EnsureRangeIsValid(long Position, long Size) { long EndPos = Position + Size; - Position &= ~AMemoryMgr.PageMask; + Position &= ~PageMask; while ((ulong)Position < (ulong)EndPos) { - EnsureAccessIsValid(Position, Perm); + EnsureAccessIsValid(Position); - Position += AMemoryMgr.PageSize; + Position += PageSize; } } - private void EnsureAccessIsValid(long Position, AMemoryPerm Perm) + private void EnsureAccessIsValid(long Position) { - if (!Manager.IsMapped(Position)) + if (!IsMapped(Position)) { throw new VmmPageFaultException(Position); } - - if (!Manager.HasPermission(Position, Perm)) - { - throw new VmmAccessViolationException(Position, Perm); - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (Ram != IntPtr.Zero) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - AMemoryWin32.Free(Ram); - } - else - { - Marshal.FreeHGlobal(Ram); - } - - Ram = IntPtr.Zero; - } } } } \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryHelper.cs b/ChocolArm64/Memory/AMemoryHelper.cs index 0a23a2f89d..ea87783438 100644 --- a/ChocolArm64/Memory/AMemoryHelper.cs +++ b/ChocolArm64/Memory/AMemoryHelper.cs @@ -26,12 +26,9 @@ namespace ChocolArm64.Memory { long Size = Marshal.SizeOf(); - if ((ulong)(Position + Size) > AMemoryMgr.AddrSize) - { - throw new ArgumentOutOfRangeException(nameof(Position)); - } + Memory.EnsureRangeIsValid(Position, Size); - IntPtr Ptr = new IntPtr((byte*)Memory.Ram + Position); + IntPtr Ptr = (IntPtr)Memory.Translate(Position); return Marshal.PtrToStructure(Ptr); } @@ -40,12 +37,9 @@ namespace ChocolArm64.Memory { long Size = Marshal.SizeOf(); - if ((ulong)(Position + Size) > AMemoryMgr.AddrSize) - { - throw new ArgumentOutOfRangeException(nameof(Position)); - } + Memory.EnsureRangeIsValid(Position, Size); - IntPtr Ptr = new IntPtr((byte*)Memory.Ram + Position); + IntPtr Ptr = (IntPtr)Memory.TranslateWrite(Position); Marshal.StructureToPtr(Value, Ptr, false); } @@ -69,15 +63,5 @@ namespace ChocolArm64.Memory return Encoding.ASCII.GetString(MS.ToArray()); } } - - public static long PageRoundUp(long Value) - { - return (Value + AMemoryMgr.PageMask) & ~AMemoryMgr.PageMask; - } - - public static long PageRoundDown(long Value) - { - return Value & ~AMemoryMgr.PageMask; - } } } \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryMapInfo.cs b/ChocolArm64/Memory/AMemoryMapInfo.cs deleted file mode 100644 index 02dd3055cc..0000000000 --- a/ChocolArm64/Memory/AMemoryMapInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace ChocolArm64.Memory -{ - public class AMemoryMapInfo - { - public long Position { get; private set; } - public long Size { get; private set; } - public int Type { get; private set; } - public int Attr { get; private set; } - - public AMemoryPerm Perm { get; private set; } - - public AMemoryMapInfo(long Position, long Size, int Type, int Attr, AMemoryPerm Perm) - { - this.Position = Position; - this.Size = Size; - this.Type = Type; - this.Attr = Attr; - this.Perm = Perm; - } - } -} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryMgr.cs b/ChocolArm64/Memory/AMemoryMgr.cs deleted file mode 100644 index 8a165b0796..0000000000 --- a/ChocolArm64/Memory/AMemoryMgr.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; - -namespace ChocolArm64.Memory -{ - public class AMemoryMgr - { - public const long RamSize = 4L * 1024 * 1024 * 1024; - public const long AddrSize = RamSize; - - private const int PTLvl0Bits = 10; - private const int PTLvl1Bits = 10; - private const int PTPageBits = 12; - - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - public const int PageSize = 1 << PTPageBits; - - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; - public const int PageMask = PageSize - 1; - - private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; - private const int PTLvl1Bit = PTPageBits; - - private enum PTMap - { - Unmapped, - Mapped - } - - private struct PTEntry - { - public PTMap Map; - public AMemoryPerm Perm; - - public int Type; - public int Attr; - - public PTEntry(PTMap Map, AMemoryPerm Perm, int Type, int Attr) - { - this.Map = Map; - this.Perm = Perm; - this.Type = Type; - this.Attr = Attr; - } - } - - private PTEntry[][] PageTable; - - public AMemoryMgr() - { - PageTable = new PTEntry[PTLvl0Size][]; - } - - public void Map(long Position, long Size, int Type, AMemoryPerm Perm) - { - SetPTEntry(Position, Size, new PTEntry(PTMap.Mapped, Perm, Type, 0)); - } - - public void Unmap(long Position, long Size) - { - SetPTEntry(Position, Size, new PTEntry(PTMap.Unmapped, 0, 0, 0)); - } - - public void Unmap(long Position, long Size, int Type) - { - SetPTEntry(Position, Size, Type, new PTEntry(PTMap.Unmapped, 0, 0, 0)); - } - - public void Reprotect(long Position, long Size, AMemoryPerm Perm) - { - Position = AMemoryHelper.PageRoundDown(Position); - - Size = AMemoryHelper.PageRoundUp(Size); - - long PagesCount = Size / PageSize; - - while (PagesCount-- > 0) - { - PTEntry Entry = GetPTEntry(Position); - - Entry.Perm = Perm; - - SetPTEntry(Position, Entry); - - Position += PageSize; - } - } - - public AMemoryMapInfo GetMapInfo(long Position) - { - if (!IsValidPosition(Position)) - { - return null; - } - - Position = AMemoryHelper.PageRoundDown(Position); - - PTEntry BaseEntry = GetPTEntry(Position); - - bool IsSameSegment(long Pos) - { - if (!IsValidPosition(Pos)) - { - return false; - } - - PTEntry Entry = GetPTEntry(Pos); - - return Entry.Map == BaseEntry.Map && - Entry.Perm == BaseEntry.Perm && - Entry.Type == BaseEntry.Type && - Entry.Attr == BaseEntry.Attr; - } - - long Start = Position; - long End = Position + PageSize; - - while (Start > 0 && IsSameSegment(Start - PageSize)) - { - Start -= PageSize; - } - - while (End < AddrSize && IsSameSegment(End)) - { - End += PageSize; - } - - long Size = End - Start; - - return new AMemoryMapInfo( - Start, - Size, - BaseEntry.Type, - BaseEntry.Attr, - BaseEntry.Perm); - } - - public void ClearAttrBit(long Position, long Size, int Bit) - { - while (Size > 0) - { - PTEntry Entry = GetPTEntry(Position); - - Entry.Attr &= ~(1 << Bit); - - SetPTEntry(Position, Entry); - - Position += PageSize; - Size -= PageSize; - } - } - - public void SetAttrBit(long Position, long Size, int Bit) - { - while (Size > 0) - { - PTEntry Entry = GetPTEntry(Position); - - Entry.Attr |= (1 << Bit); - - SetPTEntry(Position, Entry); - - Position += PageSize; - Size -= PageSize; - } - } - - public bool HasPermission(long Position, AMemoryPerm Perm) - { - return GetPTEntry(Position).Perm.HasFlag(Perm); - } - - public bool IsValidPosition(long Position) - { - if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) - { - return false; - } - - return true; - } - - public bool IsMapped(long Position) - { - if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) - { - return false; - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return false; - } - - return PageTable[L0][L1].Map != PTMap.Unmapped; - } - - private PTEntry GetPTEntry(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return default(PTEntry); - } - - return PageTable[L0][L1]; - } - - private void SetPTEntry(long Position, long Size, PTEntry Entry) - { - while (Size > 0) - { - SetPTEntry(Position, Entry); - - Position += PageSize; - Size -= PageSize; - } - } - - private void SetPTEntry(long Position, long Size, int Type, PTEntry Entry) - { - while (Size > 0) - { - if (GetPTEntry(Position).Type == Type) - { - SetPTEntry(Position, Entry); - } - - Position += PageSize; - Size -= PageSize; - } - } - - private void SetPTEntry(long Position, PTEntry Entry) - { - if (!IsValidPosition(Position)) - { - throw new ArgumentOutOfRangeException(nameof(Position)); - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - PageTable[L0] = new PTEntry[PTLvl1Size]; - } - - PageTable[L0][L1] = Entry; - } - } -} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryPerm.cs b/ChocolArm64/Memory/AMemoryPerm.cs deleted file mode 100644 index b425eb94b2..0000000000 --- a/ChocolArm64/Memory/AMemoryPerm.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ChocolArm64.Memory -{ - [Flags] - public enum AMemoryPerm - { - None = 0, - Read = 1 << 0, - Write = 1 << 1, - Execute = 1 << 2, - RW = Read | Write, - RX = Read | Execute - } -} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryWin32.cs b/ChocolArm64/Memory/AMemoryWin32.cs deleted file mode 100644 index 387ca32c2e..0000000000 --- a/ChocolArm64/Memory/AMemoryWin32.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ChocolArm64.Memory -{ - static class AMemoryWin32 - { - private const int MEM_COMMIT = 0x00001000; - private const int MEM_RESERVE = 0x00002000; - private const int MEM_WRITE_WATCH = 0x00200000; - - private const int PAGE_READWRITE = 0x04; - - private const int MEM_RELEASE = 0x8000; - - private const int WRITE_WATCH_FLAG_RESET = 1; - - [DllImport("kernel32.dll")] - private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, int flAllocationType, int flProtect); - - [DllImport("kernel32.dll")] - private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, int dwFreeType); - - [DllImport("kernel32.dll")] - private unsafe static extern int GetWriteWatch( - int dwFlags, - IntPtr lpBaseAddress, - IntPtr dwRegionSize, - IntPtr[] lpAddresses, - long* lpdwCount, - long* lpdwGranularity); - - public static IntPtr Allocate(IntPtr Size) - { - const int Flags = MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH; - - IntPtr Address = VirtualAlloc(IntPtr.Zero, Size, Flags, PAGE_READWRITE); - - if (Address == IntPtr.Zero) - { - throw new InvalidOperationException(); - } - - return Address; - } - - public static void Free(IntPtr Address) - { - VirtualFree(Address, IntPtr.Zero, MEM_RELEASE); - } - - public unsafe static int GetPageSize(IntPtr Address, IntPtr Size) - { - IntPtr[] Addresses = new IntPtr[1]; - - long Count = Addresses.Length; - - long Granularity; - - GetWriteWatch( - 0, - Address, - Size, - Addresses, - &Count, - &Granularity); - - return (int)Granularity; - } - - public unsafe static void IsRegionModified( - IntPtr Address, - IntPtr Size, - IntPtr[] Addresses, - out int AddrCount) - { - long Count = Addresses.Length; - - long Granularity; - - GetWriteWatch( - WRITE_WATCH_FLAG_RESET, - Address, - Size, - Addresses, - &Count, - &Granularity); - - AddrCount = (int)Count; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index 38f8d1c9b4..c0c06be722 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -418,6 +418,12 @@ namespace Ryujinx.HLE.Gpu.Engines Key = Vmm.GetPhysicalAddress(Key); + if (Key == -1) + { + //FIXME: Should'nt ignore invalid addresses. + return; + } + if (IsFrameBufferPosition(Key)) { //This texture is a frame buffer texture, diff --git a/Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs b/Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs index 3c25604433..d647ec7533 100644 --- a/Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs +++ b/Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.HLE.Memory; using System; using System.Collections.Generic; @@ -129,14 +130,9 @@ namespace Ryujinx.HLE.Gpu.Memory { (bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size); - if (Modified == null) - { - return true; - } - ClearCachedPagesIfNeeded(); - long PageSize = Memory.GetHostPageSize(); + long PageSize = AMemory.PageSize; EnsureResidencyInitialized(PageSize); @@ -159,9 +155,9 @@ namespace Ryujinx.HLE.Gpu.Memory while (PA < PAEnd) { - long Key = PA & ~Mask; + long Key = PA & ~AMemory.PageMask; - long PAPgEnd = Math.Min((PA + PageSize) & ~Mask, PAEnd); + long PAPgEnd = Math.Min((PA + AMemory.PageSize) & ~AMemory.PageMask, PAEnd); bool IsCached = Cache.TryGetValue(Key, out CachedPage Cp); @@ -228,7 +224,7 @@ namespace Ryujinx.HLE.Gpu.Memory { if (Residency == null) { - Residency = new HashSet[AMemoryMgr.RamSize / PageSize]; + Residency = new HashSet[DeviceMemory.RamSize / PageSize]; for (int i = 0; i < Residency.Length; i++) { diff --git a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs index f8cd676597..0c6103af80 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs @@ -72,7 +72,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - byte Pixel = CpuMem.ReadByteUnchecked(Position + Offset); + byte Pixel = CpuMem.ReadByte(Position + Offset); *(BuffPtr + OutOffs) = Pixel; @@ -105,7 +105,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - uint Pixel = (uint)CpuMem.ReadInt16Unchecked(Position + Offset); + uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset); Pixel = (Pixel & 0x001f) << 11 | (Pixel & 0x03e0) << 1 | @@ -143,7 +143,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - uint Pixel = (uint)CpuMem.ReadInt16Unchecked(Position + Offset); + uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset); Pixel = (Pixel & 0x001f) << 11 | (Pixel & 0x07e0) | @@ -180,7 +180,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - short Pixel = CpuMem.ReadInt16Unchecked(Position + Offset); + short Pixel = CpuMem.ReadInt16(Position + Offset); *(short*)(BuffPtr + OutOffs) = Pixel; @@ -213,7 +213,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - int Pixel = CpuMem.ReadInt32Unchecked(Position + Offset); + int Pixel = CpuMem.ReadInt32(Position + Offset); *(int*)(BuffPtr + OutOffs) = Pixel; @@ -246,7 +246,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Pixel = CpuMem.ReadInt64Unchecked(Position + Offset); + long Pixel = CpuMem.ReadInt64(Position + Offset); *(long*)(BuffPtr + OutOffs) = Pixel; @@ -279,8 +279,8 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long PxLow = CpuMem.ReadInt64Unchecked(Position + Offset + 0); - long PxHigh = CpuMem.ReadInt64Unchecked(Position + Offset + 8); + long PxLow = CpuMem.ReadInt64(Position + Offset + 0); + long PxHigh = CpuMem.ReadInt64(Position + Offset + 8); *(long*)(BuffPtr + OutOffs + 0) = PxLow; *(long*)(BuffPtr + OutOffs + 8) = PxHigh; @@ -314,7 +314,7 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Tile = CpuMem.ReadInt64Unchecked(Position + Offset); + long Tile = CpuMem.ReadInt64(Position + Offset); *(long*)(BuffPtr + OutOffs) = Tile; @@ -347,8 +347,8 @@ namespace Ryujinx.HLE.Gpu.Texture { long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); - long Tile0 = CpuMem.ReadInt64Unchecked(Position + Offset + 0); - long Tile1 = CpuMem.ReadInt64Unchecked(Position + Offset + 8); + long Tile0 = CpuMem.ReadInt64(Position + Offset + 0); + long Tile1 = CpuMem.ReadInt64(Position + Offset + 8); *(long*)(BuffPtr + OutOffs + 0) = Tile0; *(long*)(BuffPtr + OutOffs + 8) = Tile1; diff --git a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs index a87d4545b0..113dc6f611 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs @@ -25,7 +25,7 @@ namespace Ryujinx.HLE.Gpu.Texture int Pixel = *(int*)(BuffPtr + InOffs); - CpuMem.WriteInt32Unchecked(Position + Offset, Pixel); + CpuMem.WriteInt32(Position + Offset, Pixel); InOffs += 4; } diff --git a/Ryujinx.HLE/Hid/Hid.cs b/Ryujinx.HLE/Hid/Hid.cs index 43c040bb5d..ebc19f56c6 100644 --- a/Ryujinx.HLE/Hid/Hid.cs +++ b/Ryujinx.HLE/Hid/Hid.cs @@ -63,57 +63,21 @@ namespace Ryujinx.HLE.Input private const int HidEntryCount = 17; - private Logger Log; + private Switch Device; - private object ShMemLock; + private long HidPosition; - private (AMemory, long, long)[] ShMemPositions; - - public Hid(Logger Log) + public Hid(Switch Device, long HidPosition) { - this.Log = Log; + this.Device = Device; + this.HidPosition = HidPosition; - ShMemLock = new object(); - - ShMemPositions = new (AMemory, long, long)[0]; - } - - internal void ShMemMap(object sender, EventArgs e) - { - HSharedMem SharedMem = (HSharedMem)sender; - - lock (ShMemLock) + for (long Offset = 0; Offset < Horizon.HidSize; Offset += 8) { - ShMemPositions = SharedMem.GetVirtualPositions(); - - (AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1]; - - for (long Offset = 0; Offset < Horizon.HidSize; Offset += 8) - { - Memory.WriteInt64Unchecked(Position + Offset, 0); - } - - Log.PrintInfo(LogClass.Hid, $"HID shared memory successfully mapped to 0x{Position:x16}!"); - - Init(Memory, Position); + Device.Memory.WriteInt64(HidPosition + Offset, 0); } - } - internal void ShMemUnmap(object sender, EventArgs e) - { - HSharedMem SharedMem = (HSharedMem)sender; - - lock (ShMemLock) - { - ShMemPositions = SharedMem.GetVirtualPositions(); - } - } - - private void Init(AMemory Memory, long Position) - { InitializeJoyconPair( - Memory, - Position, JoyConColor.Body_Neon_Red, JoyConColor.Buttons_Neon_Red, JoyConColor.Body_Neon_Blue, @@ -121,14 +85,12 @@ namespace Ryujinx.HLE.Input } private void InitializeJoyconPair( - AMemory Memory, - long Position, JoyConColor LeftColorBody, JoyConColor LeftColorButtons, JoyConColor RightColorBody, JoyConColor RightColorButtons) { - long BaseControllerOffset = Position + HidControllersOffset + 8 * HidControllerSize; + long BaseControllerOffset = HidPosition + HidControllersOffset + 8 * HidControllerSize; HidControllerType Type = HidControllerType.ControllerType_Handheld; @@ -142,20 +104,20 @@ namespace Ryujinx.HLE.Input HidControllerColorDesc SplitColorDesc = 0; - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x0, (int)Type); + Device.Memory.WriteInt32(BaseControllerOffset + 0x0, (int)Type); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x4, IsHalf ? 1 : 0); + Device.Memory.WriteInt32(BaseControllerOffset + 0x4, IsHalf ? 1 : 0); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x8, (int)SingleColorDesc); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0xc, (int)SingleColorBody); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x10, (int)SingleColorButtons); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x14, (int)SplitColorDesc); + Device.Memory.WriteInt32(BaseControllerOffset + 0x8, (int)SingleColorDesc); + Device.Memory.WriteInt32(BaseControllerOffset + 0xc, (int)SingleColorBody); + Device.Memory.WriteInt32(BaseControllerOffset + 0x10, (int)SingleColorButtons); + Device.Memory.WriteInt32(BaseControllerOffset + 0x14, (int)SplitColorDesc); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x18, (int)LeftColorBody); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x1c, (int)LeftColorButtons); + Device.Memory.WriteInt32(BaseControllerOffset + 0x18, (int)LeftColorBody); + Device.Memory.WriteInt32(BaseControllerOffset + 0x1c, (int)LeftColorButtons); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x20, (int)RightColorBody); - Memory.WriteInt32Unchecked(BaseControllerOffset + 0x24, (int)RightColorButtons); + Device.Memory.WriteInt32(BaseControllerOffset + 0x20, (int)RightColorBody); + Device.Memory.WriteInt32(BaseControllerOffset + 0x24, (int)RightColorButtons); } public void SetJoyconButton( @@ -165,107 +127,95 @@ namespace Ryujinx.HLE.Input HidJoystickPosition LeftStick, HidJoystickPosition RightStick) { - lock (ShMemLock) - { - foreach ((AMemory Memory, long Position, long Size) in ShMemPositions) - { - long ControllerOffset = Position + HidControllersOffset; + long ControllerOffset = HidPosition + HidControllersOffset; - ControllerOffset += (int)ControllerId * HidControllerSize; + ControllerOffset += (int)ControllerId * HidControllerSize; - ControllerOffset += HidControllerHeaderSize; + ControllerOffset += HidControllerHeaderSize; - ControllerOffset += (int)ControllerLayout * HidControllerLayoutsSize; + ControllerOffset += (int)ControllerLayout * HidControllerLayoutsSize; - long LastEntry = Memory.ReadInt64Unchecked(ControllerOffset + 0x10); + long LastEntry = Device.Memory.ReadInt64(ControllerOffset + 0x10); - long CurrEntry = (LastEntry + 1) % HidEntryCount; + long CurrEntry = (LastEntry + 1) % HidEntryCount; - long Timestamp = GetTimestamp(); + long Timestamp = GetTimestamp(); - Memory.WriteInt64Unchecked(ControllerOffset + 0x0, Timestamp); - Memory.WriteInt64Unchecked(ControllerOffset + 0x8, HidEntryCount); - Memory.WriteInt64Unchecked(ControllerOffset + 0x10, CurrEntry); - Memory.WriteInt64Unchecked(ControllerOffset + 0x18, HidEntryCount - 1); + Device.Memory.WriteInt64(ControllerOffset + 0x0, Timestamp); + Device.Memory.WriteInt64(ControllerOffset + 0x8, HidEntryCount); + Device.Memory.WriteInt64(ControllerOffset + 0x10, CurrEntry); + Device.Memory.WriteInt64(ControllerOffset + 0x18, HidEntryCount - 1); - ControllerOffset += HidControllersLayoutHeaderSize; + ControllerOffset += HidControllersLayoutHeaderSize; - long LastEntryOffset = ControllerOffset + LastEntry * HidControllersInputEntrySize; + long LastEntryOffset = ControllerOffset + LastEntry * HidControllersInputEntrySize; - ControllerOffset += CurrEntry * HidControllersInputEntrySize; + ControllerOffset += CurrEntry * HidControllersInputEntrySize; - long SampleCounter = Memory.ReadInt64Unchecked(LastEntryOffset) + 1; + long SampleCounter = Device.Memory.ReadInt64(LastEntryOffset) + 1; - Memory.WriteInt64Unchecked(ControllerOffset + 0x0, SampleCounter); - Memory.WriteInt64Unchecked(ControllerOffset + 0x8, SampleCounter); + Device.Memory.WriteInt64(ControllerOffset + 0x0, SampleCounter); + Device.Memory.WriteInt64(ControllerOffset + 0x8, SampleCounter); - Memory.WriteInt64Unchecked(ControllerOffset + 0x10, (uint)Buttons); + Device.Memory.WriteInt64(ControllerOffset + 0x10, (uint)Buttons); - Memory.WriteInt32Unchecked(ControllerOffset + 0x18, LeftStick.DX); - Memory.WriteInt32Unchecked(ControllerOffset + 0x1c, LeftStick.DY); + Device.Memory.WriteInt32(ControllerOffset + 0x18, LeftStick.DX); + Device.Memory.WriteInt32(ControllerOffset + 0x1c, LeftStick.DY); - Memory.WriteInt32Unchecked(ControllerOffset + 0x20, RightStick.DX); - Memory.WriteInt32Unchecked(ControllerOffset + 0x24, RightStick.DY); + Device.Memory.WriteInt32(ControllerOffset + 0x20, RightStick.DX); + Device.Memory.WriteInt32(ControllerOffset + 0x24, RightStick.DY); - Memory.WriteInt64Unchecked(ControllerOffset + 0x28, - (uint)HidControllerConnState.Controller_State_Connected | - (uint)HidControllerConnState.Controller_State_Wired); - } - } + Device.Memory.WriteInt64(ControllerOffset + 0x28, + (uint)HidControllerConnState.Controller_State_Connected | + (uint)HidControllerConnState.Controller_State_Wired); } public void SetTouchPoints(params HidTouchPoint[] Points) { - lock (ShMemLock) + long TouchScreenOffset = HidPosition + HidTouchScreenOffset; + + long LastEntry = Device.Memory.ReadInt64(TouchScreenOffset + 0x10); + + long CurrEntry = (LastEntry + 1) % HidEntryCount; + + long Timestamp = GetTimestamp(); + + Device.Memory.WriteInt64(TouchScreenOffset + 0x0, Timestamp); + Device.Memory.WriteInt64(TouchScreenOffset + 0x8, HidEntryCount); + Device.Memory.WriteInt64(TouchScreenOffset + 0x10, CurrEntry); + Device.Memory.WriteInt64(TouchScreenOffset + 0x18, HidEntryCount - 1); + Device.Memory.WriteInt64(TouchScreenOffset + 0x20, Timestamp); + + long TouchEntryOffset = TouchScreenOffset + HidTouchHeaderSize; + + long LastEntryOffset = TouchEntryOffset + LastEntry * HidTouchEntrySize; + + long SampleCounter = Device.Memory.ReadInt64(LastEntryOffset) + 1; + + TouchEntryOffset += CurrEntry * HidTouchEntrySize; + + Device.Memory.WriteInt64(TouchEntryOffset + 0x0, SampleCounter); + Device.Memory.WriteInt64(TouchEntryOffset + 0x8, Points.Length); + + TouchEntryOffset += HidTouchEntryHeaderSize; + + const int Padding = 0; + + int Index = 0; + + foreach (HidTouchPoint Point in Points) { - foreach ((AMemory Memory, long Position, long Size) in ShMemPositions) - { - long TouchScreenOffset = Position + HidTouchScreenOffset; + Device.Memory.WriteInt64(TouchEntryOffset + 0x0, Timestamp); + Device.Memory.WriteInt32(TouchEntryOffset + 0x8, Padding); + Device.Memory.WriteInt32(TouchEntryOffset + 0xc, Index++); + Device.Memory.WriteInt32(TouchEntryOffset + 0x10, Point.X); + Device.Memory.WriteInt32(TouchEntryOffset + 0x14, Point.Y); + Device.Memory.WriteInt32(TouchEntryOffset + 0x18, Point.DiameterX); + Device.Memory.WriteInt32(TouchEntryOffset + 0x1c, Point.DiameterY); + Device.Memory.WriteInt32(TouchEntryOffset + 0x20, Point.Angle); + Device.Memory.WriteInt32(TouchEntryOffset + 0x24, Padding); - long LastEntry = Memory.ReadInt64Unchecked(TouchScreenOffset + 0x10); - - long CurrEntry = (LastEntry + 1) % HidEntryCount; - - long Timestamp = GetTimestamp(); - - Memory.WriteInt64Unchecked(TouchScreenOffset + 0x0, Timestamp); - Memory.WriteInt64Unchecked(TouchScreenOffset + 0x8, HidEntryCount); - Memory.WriteInt64Unchecked(TouchScreenOffset + 0x10, CurrEntry); - Memory.WriteInt64Unchecked(TouchScreenOffset + 0x18, HidEntryCount - 1); - Memory.WriteInt64Unchecked(TouchScreenOffset + 0x20, Timestamp); - - long TouchEntryOffset = TouchScreenOffset + HidTouchHeaderSize; - - long LastEntryOffset = TouchEntryOffset + LastEntry * HidTouchEntrySize; - - long SampleCounter = Memory.ReadInt64Unchecked(LastEntryOffset) + 1; - - TouchEntryOffset += CurrEntry * HidTouchEntrySize; - - Memory.WriteInt64Unchecked(TouchEntryOffset + 0x0, SampleCounter); - Memory.WriteInt64Unchecked(TouchEntryOffset + 0x8, Points.Length); - - TouchEntryOffset += HidTouchEntryHeaderSize; - - const int Padding = 0; - - int Index = 0; - - foreach (HidTouchPoint Point in Points) - { - Memory.WriteInt64Unchecked(TouchEntryOffset + 0x0, Timestamp); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x8, Padding); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0xc, Index++); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x10, Point.X); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x14, Point.Y); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x18, Point.DiameterX); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x1c, Point.DiameterY); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x20, Point.Angle); - Memory.WriteInt32Unchecked(TouchEntryOffset + 0x24, Padding); - - TouchEntryOffset += HidTouchEntryTouchSize; - } - } + TouchEntryOffset += HidTouchEntryTouchSize; } } diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs index 84f5ff3904..ba5f8d7ed2 100644 --- a/Ryujinx.HLE/Loaders/Executable.cs +++ b/Ryujinx.HLE/Loaders/Executable.cs @@ -1,6 +1,8 @@ using ChocolArm64.Memory; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.OsHle; +using Ryujinx.HLE.OsHle.Handles; +using Ryujinx.HLE.OsHle.Utilities; using System.Collections.Generic; using System.IO; @@ -18,12 +20,14 @@ namespace Ryujinx.HLE.Loaders public string FilePath { get; private set; } - private AMemory Memory; - public long ImageBase { get; private set; } public long ImageEnd { get; private set; } - public Executable(IExecutable Exe, AMemory Memory, long ImageBase) + private AMemory Memory; + + private KMemoryManager MemoryManager; + + public Executable(IExecutable Exe, KMemoryManager MemoryManager, AMemory Memory, long ImageBase) { Dynamic = new List(); @@ -36,23 +40,34 @@ namespace Ryujinx.HLE.Loaders Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, "")); } - this.Memory = Memory; - this.ImageBase = ImageBase; - this.ImageEnd = ImageBase; + this.Memory = Memory; + this.MemoryManager = MemoryManager; + this.ImageBase = ImageBase; + this.ImageEnd = ImageBase; - WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX); - WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.CodeMutable, AMemoryPerm.Read); - WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.CodeMutable, AMemoryPerm.RW); + long TextPosition = ImageBase + (uint)Exe.TextOffset; + long ROPosition = ImageBase + (uint)Exe.ROOffset; + long DataPosition = ImageBase + (uint)Exe.DataOffset; + + long TextSize = (uint)IntUtils.AlignUp(Exe.Text.Length, KMemoryManager.PageSize); + long ROSize = (uint)IntUtils.AlignUp(Exe.RO.Length, KMemoryManager.PageSize); + long DataSize = (uint)IntUtils.AlignUp(Exe.Data.Length, KMemoryManager.PageSize); + + long DataAndBssSize = (uint)IntUtils.AlignUp(Exe.BssSize, KMemoryManager.PageSize) + DataSize; + + ImageEnd = DataPosition + DataAndBssSize; + + MemoryManager.HleMapProcessCode(TextPosition, TextSize + ROSize + DataAndBssSize); + + MemoryManager.SetProcessMemoryPermission(ROPosition, ROSize, MemoryPermission.Read); + MemoryManager.SetProcessMemoryPermission(DataPosition, DataAndBssSize, MemoryPermission.ReadAndWrite); + + Memory.WriteBytes(TextPosition, Exe.Text); + Memory.WriteBytes(ROPosition, Exe.RO); + Memory.WriteBytes(DataPosition, Exe.Data); if (Exe.Mod0Offset == 0) { - int BssOffset = Exe.DataOffset + Exe.Data.Length; - int BssSize = Exe.BssSize; - - MapBss(ImageBase + BssOffset, BssSize); - - ImageEnd = ImageBase + BssOffset + BssSize; - return; } @@ -66,10 +81,6 @@ namespace Ryujinx.HLE.Loaders long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset; long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset; - MapBss(BssStartOffset, BssEndOffset - BssStartOffset); - - ImageEnd = BssEndOffset; - while (true) { long TagVal = Memory.ReadInt64(DynamicOffset + 0); @@ -102,24 +113,6 @@ namespace Ryujinx.HLE.Loaders } } - private void WriteData( - long Position, - byte[] Data, - MemoryType Type, - AMemoryPerm Perm) - { - Memory.Manager.Map(Position, Data.Length, (int)Type, AMemoryPerm.Write); - - Memory.WriteBytes(Position, Data); - - Memory.Manager.Reprotect(Position, Data.Length, Perm); - } - - private void MapBss(long Position, long Size) - { - Memory.Manager.Map(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW); - } - private ElfRel GetRelocation(long Position) { long Offset = Memory.ReadInt64(Position + 0); diff --git a/Ryujinx.HLE/Memory/ArenaAllocator.cs b/Ryujinx.HLE/Memory/ArenaAllocator.cs new file mode 100644 index 0000000000..df73dd0b33 --- /dev/null +++ b/Ryujinx.HLE/Memory/ArenaAllocator.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.Memory +{ + class ArenaAllocator + { + private class Region + { + public long Position { get; set; } + public long Size { get; set; } + + public Region(long Position, long Size) + { + this.Position = Position; + this.Size = Size; + } + } + + private LinkedList FreeRegions; + + public ArenaAllocator(long ArenaSize) + { + FreeRegions = new LinkedList(); + + FreeRegions.AddFirst(new Region(0, ArenaSize)); + } + + public bool TryAllocate(long Size, out long Position) + { + LinkedListNode Node = FreeRegions.First; + + while (Node != null) + { + Region Rg = Node.Value; + + if ((ulong)Rg.Size >= (ulong)Size) + { + Position = Rg.Position; + + Rg.Position += Size; + Rg.Size -= Size; + + return true; + } + + Node = Node.Next; + } + + Position = 0; + + return false; + } + + public void Free(long Position, long Size) + { + long End = Position + Size; + + Region NewRg = new Region(Position, Size); + + LinkedListNode Node = FreeRegions.First; + LinkedListNode PrevSz = Node; + + while (Node != null) + { + LinkedListNode NextNode = Node.Next; + + Region Rg = Node.Value; + + long RgEnd = Rg.Position + Rg.Size; + + if (Rg.Position == End) + { + NewRg.Size += Rg.Size; + + FreeRegions.Remove(Node); + } + else if (RgEnd == Position) + { + NewRg.Position = Rg.Position; + NewRg.Size += Rg.Size; + + FreeRegions.Remove(Node); + } + else if ((ulong)Rg.Size < (ulong)NewRg.Size && + (ulong)Rg.Size > (ulong)PrevSz.Value.Size) + { + PrevSz = Node; + } + + Node = NextNode; + } + + if ((ulong)PrevSz.Value.Size < (ulong)Size) + { + FreeRegions.AddAfter(PrevSz, NewRg); + } + else + { + FreeRegions.AddFirst(NewRg); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Memory/DeviceMemory.cs b/Ryujinx.HLE/Memory/DeviceMemory.cs new file mode 100644 index 0000000000..e1de72f86f --- /dev/null +++ b/Ryujinx.HLE/Memory/DeviceMemory.cs @@ -0,0 +1,115 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.Memory +{ + class DeviceMemory : IDisposable + { + public const long RamSize = 4L * 1024 * 1024 * 1024; + + public ArenaAllocator Allocator { get; private set; } + + public IntPtr RamPointer { get; private set; } + + private unsafe byte* RamPtr; + + public unsafe DeviceMemory() + { + Allocator = new ArenaAllocator(RamSize); + + RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize)); + + RamPtr = (byte*)RamPointer; + } + + public sbyte ReadSByte(long Position) + { + return (sbyte)ReadByte(Position); + } + + public short ReadInt16(long Position) + { + return (short)ReadUInt16(Position); + } + + public int ReadInt32(long Position) + { + return (int)ReadUInt32(Position); + } + + public long ReadInt64(long Position) + { + return (long)ReadUInt64(Position); + } + + public unsafe byte ReadByte(long Position) + { + return *((byte*)(RamPtr + Position)); + } + + public unsafe ushort ReadUInt16(long Position) + { + return *((ushort*)(RamPtr + Position)); + } + + public unsafe uint ReadUInt32(long Position) + { + return *((uint*)(RamPtr + Position)); + } + + public unsafe ulong ReadUInt64(long Position) + { + return *((ulong*)(RamPtr + Position)); + } + + public void WriteSByte(long Position, sbyte Value) + { + WriteByte(Position, (byte)Value); + } + + public void WriteInt16(long Position, short Value) + { + WriteUInt16(Position, (ushort)Value); + } + + public void WriteInt32(long Position, int Value) + { + WriteUInt32(Position, (uint)Value); + } + + public void WriteInt64(long Position, long Value) + { + WriteUInt64(Position, (ulong)Value); + } + + public unsafe void WriteByte(long Position, byte Value) + { + *((byte*)(RamPtr + Position)) = Value; + } + + public unsafe void WriteUInt16(long Position, ushort Value) + { + *((ushort*)(RamPtr + Position)) = Value; + } + + public unsafe void WriteUInt32(long Position, uint Value) + { + *((uint*)(RamPtr + Position)) = Value; + } + + public unsafe void WriteUInt64(long Position, ulong Value) + { + *((ulong*)(RamPtr + Position)) = Value; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + Marshal.FreeHGlobal(RamPointer); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/HTransferMem.cs b/Ryujinx.HLE/OsHle/Handles/HTransferMem.cs deleted file mode 100644 index 2969a2bae4..0000000000 --- a/Ryujinx.HLE/OsHle/Handles/HTransferMem.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class HTransferMem - { - public AMemory Memory { get; private set; } - public AMemoryPerm Perm { get; private set; } - - public long Position { get; private set; } - public long Size { get; private set; } - - public HTransferMem(AMemory Memory, AMemoryPerm Perm, long Position, long Size) - { - this.Memory = Memory; - this.Perm = Perm; - this.Position = Position; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs b/Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs new file mode 100644 index 0000000000..e33b6cb9b3 --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/KMemoryBlock.cs @@ -0,0 +1,43 @@ +namespace Ryujinx.HLE.OsHle.Handles +{ + class KMemoryBlock + { + public long BasePosition { get; set; } + public long PagesCount { get; set; } + + public MemoryState State { get; set; } + public MemoryPermission Permission { get; set; } + public MemoryAttribute Attribute { get; set; } + + public int IpcRefCount { get; set; } + public int DeviceRefCount { get; set; } + + public KMemoryBlock( + long BasePosition, + long PagesCount, + MemoryState State, + MemoryPermission Permission, + MemoryAttribute Attribute) + { + this.BasePosition = BasePosition; + this.PagesCount = PagesCount; + this.State = State; + this.Attribute = Attribute; + this.Permission = Permission; + } + + public KMemoryInfo GetInfo() + { + long Size = PagesCount * KMemoryManager.PageSize; + + return new KMemoryInfo( + BasePosition, + Size, + State, + Permission, + Attribute, + IpcRefCount, + DeviceRefCount); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs b/Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs new file mode 100644 index 0000000000..3f79f000d5 --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/KMemoryInfo.cs @@ -0,0 +1,33 @@ +namespace Ryujinx.HLE.OsHle.Handles +{ + class KMemoryInfo + { + public long Position { get; private set; } + public long Size { get; private set; } + + public MemoryState State { get; private set; } + public MemoryPermission Permission { get; private set; } + public MemoryAttribute Attribute { get; private set; } + + public int IpcRefCount { get; private set; } + public int DeviceRefCount { get; private set; } + + public KMemoryInfo( + long Position, + long Size, + MemoryState State, + MemoryPermission Permission, + MemoryAttribute Attribute, + int IpcRefCount, + int DeviceRefCount) + { + this.Position = Position; + this.Size = Size; + this.State = State; + this.Attribute = Attribute; + this.Permission = Permission; + this.IpcRefCount = IpcRefCount; + this.DeviceRefCount = DeviceRefCount; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs b/Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs new file mode 100644 index 0000000000..b23a6c78d4 --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/KMemoryManager.cs @@ -0,0 +1,745 @@ +using ChocolArm64.Memory; +using Ryujinx.HLE.Memory; +using Ryujinx.HLE.OsHle.Kernel; +using System; +using System.Collections.Generic; + +using static Ryujinx.HLE.OsHle.ErrorCode; + +namespace Ryujinx.HLE.OsHle.Handles +{ + class KMemoryManager + { + public const int PageSize = 0x1000; + + private LinkedList Blocks; + + private AMemory CpuMemoryManager; + + private ArenaAllocator Allocator; + + public long AddrSpaceStart { get; private set; } + public long AddrSpaceEnd { get; private set; } + + public long HeapRegionStart { get; private set; } + public long HeapRegionEnd { get; private set; } + + public long TlsIoRegionStart { get; private set; } + public long TlsIoRegionEnd { get; private set; } + + private long CurrentHeapAddr; + + public KMemoryManager(AMemory CpuMemoryManager, ArenaAllocator Allocator) + { + this.CpuMemoryManager = CpuMemoryManager; + this.Allocator = Allocator; + + AddrSpaceStart = 0; + AddrSpaceEnd = MemoryRegions.AddrSpaceStart + MemoryRegions.AddrSpaceSize; + + HeapRegionStart = MemoryRegions.HeapRegionAddress; + HeapRegionEnd = MemoryRegions.HeapRegionAddress + MemoryRegions.HeapRegionSize; + + CurrentHeapAddr = HeapRegionStart; + + Blocks = new LinkedList(); + + long AddrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize; + + InsertBlockUnsafe( + AddrSpaceStart, + AddrSpacePagesCount, + MemoryState.Unmapped, + MemoryPermission.None, + MemoryAttribute.None); + } + + public void HleMapProcessCode(long Position, long Size) + { + long PagesCount = Size / PageSize; + + if (!Allocator.TryAllocate(Size, out long PA)) + { + throw new InvalidOperationException(); + } + + lock (Blocks) + { + InsertBlockUnsafe( + Position, + PagesCount, + MemoryState.CodeStatic, + MemoryPermission.ReadAndExecute, + MemoryAttribute.None); + + CpuMemoryManager.Map(Position, PA, Size); + } + } + + public void HleMapCustom(long Position, long Size, MemoryState State, MemoryPermission Permission) + { + long PagesCount = Size / PageSize; + + if (!Allocator.TryAllocate(Size, out long PA)) + { + throw new InvalidOperationException(); + } + + lock (Blocks) + { + InsertBlockUnsafe(Position, PagesCount, State, Permission, MemoryAttribute.None); + + CpuMemoryManager.Map(Position, PA, Size); + } + } + + public long TrySetHeapSize(long Size, out long Position) + { + Position = 0; + + if ((ulong)Size > (ulong)(HeapRegionEnd - HeapRegionStart)) + { + return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); + } + + bool Success = false; + + long CurrentHeapSize = GetHeapSize(); + + if ((ulong)CurrentHeapSize <= (ulong)Size) + { + //Expand. + long DiffSize = Size - CurrentHeapSize; + + if (!Allocator.TryAllocate(DiffSize, out long PA)) + { + return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory); + } + + lock (Blocks) + { + if (Success = CheckUnmappedUnsafe(CurrentHeapAddr, DiffSize)) + { + long PagesCount = DiffSize / PageSize; + + InsertBlockUnsafe( + CurrentHeapAddr, + PagesCount, + MemoryState.Heap, + MemoryPermission.ReadAndWrite, + MemoryAttribute.None); + + CpuMemoryManager.Map(CurrentHeapAddr, PA, DiffSize); + } + } + } + else + { + //Shrink. + long FreeAddr = HeapRegionStart + Size; + long DiffSize = CurrentHeapSize - Size; + + lock (Blocks) + { + Success = CheckRangeUnsafe( + FreeAddr, + DiffSize, + MemoryState.Mask, + MemoryState.Heap, + MemoryPermission.Mask, + MemoryPermission.ReadAndWrite, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out _, + out _, + out _); + + if (Success) + { + long PagesCount = DiffSize / PageSize; + + InsertBlockUnsafe( + FreeAddr, + PagesCount, + MemoryState.Unmapped, + MemoryPermission.None, + MemoryAttribute.None); + + CpuMemoryManager.Unmap(FreeAddr, DiffSize); + } + } + } + + CurrentHeapAddr = HeapRegionStart + Size; + + if (Success) + { + Position = HeapRegionStart; + + return 0; + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long GetHeapSize() + { + return CurrentHeapAddr - HeapRegionStart; + } + + public long SetMemoryAttribute( + long Position, + long Size, + MemoryAttribute AttributeMask, + MemoryAttribute AttributeValue) + { + lock (Blocks) + { + if (CheckRangeUnsafe( + Position, + Size, + MemoryState.AttributeChangeAllowed, + MemoryState.AttributeChangeAllowed, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.BorrowedAndIpcMapped, + MemoryAttribute.None, + MemoryAttribute.DeviceMappedAndUncached, + out MemoryState State, + out MemoryPermission Permission, + out MemoryAttribute Attribute)) + { + long PagesCount = Size / PageSize; + + Attribute &= ~AttributeMask; + Attribute |= AttributeMask & AttributeValue; + + InsertBlockUnsafe(Position, PagesCount, State, Permission, Attribute); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public KMemoryInfo QueryMemory(long Position) + { + if ((ulong)Position >= (ulong)AddrSpaceStart && + (ulong)Position < (ulong)AddrSpaceEnd) + { + lock (Blocks) + { + return FindBlockUnsafe(Position).GetInfo(); + } + } + else + { + return new KMemoryInfo( + AddrSpaceEnd, + -AddrSpaceEnd, + MemoryState.Reserved, + MemoryPermission.None, + MemoryAttribute.None, + 0, + 0); + } + } + + public long Map(long Src, long Dst, long Size) + { + long PagesCount = Size / PageSize; + + bool Success; + + lock (Blocks) + { + Success = CheckRangeUnsafe( + Src, + Size, + MemoryState.MapAllowed, + MemoryState.MapAllowed, + MemoryPermission.Mask, + MemoryPermission.ReadAndWrite, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState SrcState, + out _, + out _); + + Success &= CheckUnmappedUnsafe(Dst, Size); + + if (Success) + { + InsertBlockUnsafe( + Src, + PagesCount, + SrcState, + MemoryPermission.None, + MemoryAttribute.Borrowed); + + InsertBlockUnsafe( + Dst, + PagesCount, + MemoryState.MappedMemory, + MemoryPermission.ReadAndWrite, + MemoryAttribute.None); + + long PA = CpuMemoryManager.GetPhysicalAddress(Src); + + CpuMemoryManager.Map(Dst, PA, Size); + } + } + + return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long Unmap(long Src, long Dst, long Size) + { + long PagesCount = Size / PageSize; + + bool Success; + + lock (Blocks) + { + Success = CheckRangeUnsafe( + Src, + Size, + MemoryState.MapAllowed, + MemoryState.MapAllowed, + MemoryPermission.Mask, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.Borrowed, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState SrcState, + out _, + out _); + + Success &= CheckRangeUnsafe( + Dst, + Size, + MemoryState.Mask, + MemoryState.MappedMemory, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out _, + out _, + out _); + + if (Success) + { + InsertBlockUnsafe( + Src, + PagesCount, + SrcState, + MemoryPermission.ReadAndWrite, + MemoryAttribute.None); + + InsertBlockUnsafe( + Dst, + PagesCount, + MemoryState.Unmapped, + MemoryPermission.None, + MemoryAttribute.None); + + CpuMemoryManager.Unmap(Dst, Size); + } + } + + return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long MapSharedMemory(KSharedMemory SharedMemory, MemoryPermission Permission, long Position) + { + lock (Blocks) + { + if (CheckUnmappedUnsafe(Position, SharedMemory.Size)) + { + long PagesCount = SharedMemory.Size / PageSize; + + InsertBlockUnsafe( + Position, + PagesCount, + MemoryState.SharedMemory, + Permission, + MemoryAttribute.None); + + CpuMemoryManager.Map(Position, SharedMemory.PA, SharedMemory.Size); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long UnmapSharedMemory(long Position, long Size) + { + lock (Blocks) + { + if (CheckRangeUnsafe( + Position, + Size, + MemoryState.Mask, + MemoryState.SharedMemory, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out _)) + { + long PagesCount = Size / PageSize; + + InsertBlockUnsafe( + Position, + PagesCount, + MemoryState.Unmapped, + MemoryPermission.None, + MemoryAttribute.None); + + CpuMemoryManager.Unmap(Position, Size); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long ReserveTransferMemory(long Position, long Size, MemoryPermission Permission) + { + lock (Blocks) + { + if (CheckRangeUnsafe( + Position, + Size, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryPermission.Mask, + MemoryPermission.ReadAndWrite, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out MemoryAttribute Attribute)) + { + long PagesCount = Size / PageSize; + + Attribute |= MemoryAttribute.Borrowed; + + InsertBlockUnsafe( + Position, + PagesCount, + State, + Permission, + Attribute); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long ResetTransferMemory(long Position, long Size) + { + lock (Blocks) + { + if (CheckRangeUnsafe( + Position, + Size, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.Borrowed, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out _)) + { + long PagesCount = Size / PageSize; + + InsertBlockUnsafe( + Position, + PagesCount, + State, + MemoryPermission.ReadAndWrite, + MemoryAttribute.None); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + public long SetProcessMemoryPermission(long Position, long Size, MemoryPermission Permission) + { + lock (Blocks) + { + if (CheckRangeUnsafe( + Position, + Size, + MemoryState.ProcessPermissionChangeAllowed, + MemoryState.ProcessPermissionChangeAllowed, + MemoryPermission.None, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out MemoryState State, + out _, + out _)) + { + if (State == MemoryState.CodeStatic) + { + State = MemoryState.CodeMutable; + } + else if (State == MemoryState.ModCodeStatic) + { + State = MemoryState.ModCodeMutable; + } + else + { + throw new InvalidOperationException(); + } + + long PagesCount = Size / PageSize; + + InsertBlockUnsafe(Position, PagesCount, State, Permission, MemoryAttribute.None); + + return 0; + } + } + + return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + } + + private bool CheckUnmappedUnsafe(long Dst, long Size) + { + return CheckRangeUnsafe( + Dst, + Size, + MemoryState.Mask, + MemoryState.Unmapped, + MemoryPermission.Mask, + MemoryPermission.None, + MemoryAttribute.Mask, + MemoryAttribute.None, + MemoryAttribute.IpcAndDeviceMapped, + out _, + out _, + out _); + } + + private bool CheckRangeUnsafe( + long Dst, + long Size, + MemoryState StateMask, + MemoryState StateExpected, + MemoryPermission PermissionMask, + MemoryPermission PermissionExpected, + MemoryAttribute AttributeMask, + MemoryAttribute AttributeExpected, + MemoryAttribute AttributeIgnoreMask, + out MemoryState OutState, + out MemoryPermission OutPermission, + out MemoryAttribute OutAttribute) + { + KMemoryInfo BlkInfo = FindBlockUnsafe(Dst).GetInfo(); + + ulong Start = (ulong)Dst; + ulong End = (ulong)Size + Start; + + if (End <= (ulong)(BlkInfo.Position + BlkInfo.Size)) + { + if ((BlkInfo.Attribute & AttributeMask) == AttributeExpected && + (BlkInfo.State & StateMask) == StateExpected && + (BlkInfo.Permission & PermissionMask) == PermissionExpected) + { + OutState = BlkInfo.State; + OutPermission = BlkInfo.Permission; + OutAttribute = BlkInfo.Attribute & ~AttributeIgnoreMask; + + return true; + } + } + + OutState = MemoryState.Unmapped; + OutPermission = MemoryPermission.None; + OutAttribute = MemoryAttribute.None; + + return false; + } + + private void InsertBlockUnsafe( + long BasePosition, + long PagesCount, + MemoryState State, + MemoryPermission Permission, + MemoryAttribute Attribute) + { + KMemoryBlock Block = new KMemoryBlock( + BasePosition, + PagesCount, + State, + Permission, + Attribute); + + ulong Start = (ulong)BasePosition; + ulong End = (ulong)PagesCount * PageSize + Start; + + LinkedListNode NewNode = null; + + LinkedListNode Node = Blocks.First; + + while (Node != null) + { + KMemoryBlock CurrBlock = Node.Value; + + LinkedListNode NextNode = Node.Next; + + ulong CurrStart = (ulong)CurrBlock.BasePosition; + ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart; + + if (Start < CurrEnd && CurrStart < End) + { + if (Start >= CurrStart && End <= CurrEnd) + { + Block.Attribute |= CurrBlock.Attribute & MemoryAttribute.IpcAndDeviceMapped; + } + + if (Start > CurrStart && End < CurrEnd) + { + CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); + + Node = Blocks.AddAfter(Node, Block); + + KMemoryBlock NewBlock = new KMemoryBlock( + (long)End, + (long)((CurrEnd - End) / PageSize), + CurrBlock.State, + CurrBlock.Permission, + CurrBlock.Attribute); + + Blocks.AddAfter(Node, NewBlock); + + return; + } + else if (Start <= CurrStart && End < CurrEnd) + { + CurrBlock.BasePosition = (long)End; + + CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize); + + if (NewNode == null) + { + NewNode = Blocks.AddBefore(Node, Block); + } + } + else if (Start > CurrStart && End >= CurrEnd) + { + CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize); + + if (NewNode == null) + { + NewNode = Blocks.AddAfter(Node, Block); + } + } + else + { + if (NewNode == null) + { + NewNode = Blocks.AddBefore(Node, Block); + } + + Blocks.Remove(Node); + } + } + + Node = NextNode; + } + + if (NewNode == null) + { + NewNode = Blocks.AddFirst(Block); + } + + if (NewNode.Previous != null) + { + KMemoryBlock Previous = NewNode.Previous.Value; + + if (BlockStateEquals(Block, Previous)) + { + Blocks.Remove(NewNode.Previous); + + Block.BasePosition = Previous.BasePosition; + + Start = (ulong)Block.BasePosition; + } + } + + if (NewNode.Next != null) + { + KMemoryBlock Next = NewNode.Next.Value; + + if (BlockStateEquals(Block, Next)) + { + Blocks.Remove(NewNode.Next); + + End = (ulong)(Next.BasePosition + Next.PagesCount * PageSize); + } + } + + Block.PagesCount = (long)((End - Start) / PageSize); + } + + private static bool BlockStateEquals(KMemoryBlock LHS, KMemoryBlock RHS) + { + return LHS.State == RHS.State && + LHS.Permission == RHS.Permission && + LHS.Attribute == RHS.Attribute && + LHS.DeviceRefCount == RHS.DeviceRefCount && + LHS.IpcRefCount == RHS.IpcRefCount; + } + + private KMemoryBlock FindBlockUnsafe(long Position) + { + ulong Addr = (ulong)Position; + + lock (Blocks) + { + LinkedListNode Node = Blocks.First; + + while (Node != null) + { + KMemoryBlock Block = Node.Value; + + ulong Start = (ulong)Block.BasePosition; + ulong End = (ulong)Block.PagesCount * PageSize + Start; + + if (Start <= Addr && End - 1 >= Addr) + { + return Block; + } + + Node = Node.Next; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs b/Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs new file mode 100644 index 0000000000..b7859e7031 --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/KSharedMemory.cs @@ -0,0 +1,18 @@ +using ChocolArm64.Memory; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.OsHle.Handles +{ + class KSharedMemory + { + public long PA { get; private set; } + public long Size { get; private set; } + + public KSharedMemory(long PA, long Size) + { + this.PA = PA; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs b/Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs new file mode 100644 index 0000000000..5f9c040947 --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/KTransferMemory.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.OsHle.Handles +{ + class KTransferMemory + { + public long Position { get; private set; } + public long Size { get; private set; } + + public KTransferMemory(long Position, long Size) + { + this.Position = Position; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs b/Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs new file mode 100644 index 0000000000..e234d7f08b --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/MemoryAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace Ryujinx.HLE.OsHle.Handles +{ + [Flags] + enum MemoryAttribute : byte + { + None = 0, + Mask = 0xff, + + Borrowed = 1 << 0, + IpcMapped = 1 << 1, + DeviceMapped = 1 << 2, + Uncached = 1 << 3, + + IpcAndDeviceMapped = IpcMapped | DeviceMapped, + + BorrowedAndIpcMapped = Borrowed | IpcMapped, + + DeviceMappedAndUncached = DeviceMapped | Uncached + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs b/Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs new file mode 100644 index 0000000000..416f171e2d --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/MemoryPermission.cs @@ -0,0 +1,18 @@ +using System; + +namespace Ryujinx.HLE.OsHle.Handles +{ + [Flags] + enum MemoryPermission : byte + { + None = 0, + Mask = 0xff, + + Read = 1 << 0, + Write = 1 << 1, + Execute = 1 << 2, + + ReadAndWrite = Read | Write, + ReadAndExecute = Read | Execute + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/MemoryState.cs b/Ryujinx.HLE/OsHle/Handles/MemoryState.cs new file mode 100644 index 0000000000..5437d6a33c --- /dev/null +++ b/Ryujinx.HLE/OsHle/Handles/MemoryState.cs @@ -0,0 +1,49 @@ +using System; + +namespace Ryujinx.HLE.OsHle +{ + [Flags] + enum MemoryState : uint + { + Unmapped = 0x00000000, + Io = 0x00002001, + Normal = 0x00042002, + CodeStatic = 0x00DC7E03, + CodeMutable = 0x03FEBD04, + Heap = 0x037EBD05, + SharedMemory = 0x00402006, + ModCodeStatic = 0x00DD7E08, + ModCodeMutable = 0x03FFBD09, + IpcBuffer0 = 0x005C3C0A, + MappedMemory = 0x005C3C0B, + ThreadLocal = 0x0040200C, + TransferMemoryIsolated = 0x015C3C0D, + TransferMemory = 0x005C380E, + ProcessMemory = 0x0040380F, + Reserved = 0x00000010, + IpcBuffer1 = 0x005C3811, + IpcBuffer3 = 0x004C2812, + KernelStack = 0x00002013, + CodeReadOnly = 0x00402214, + CodeWritable = 0x00402015, + Mask = 0xffffffff, + + PermissionChangeAllowed = 1 << 8, + ForceReadWritableByDebugSyscalls = 1 << 9, + IpcSendAllowedType0 = 1 << 10, + IpcSendAllowedType3 = 1 << 11, + IpcSendAllowedType1 = 1 << 12, + ProcessPermissionChangeAllowed = 1 << 14, + MapAllowed = 1 << 15, + UnmapProcessCodeMemoryAllowed = 1 << 16, + TransferMemoryAllowed = 1 << 17, + QueryPhysicalAddressAllowed = 1 << 18, + MapDeviceAllowed = 1 << 19, + MapDeviceAlignedAllowed = 1 << 20, + IpcBufferAllowed = 1 << 21, + IsPoolAllocated = 1 << 22, + MapProcessAllowed = 1 << 23, + AttributeChangeAllowed = 1 << 24, + CodeMemoryAllowed = 1 << 25 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Homebrew.cs b/Ryujinx.HLE/OsHle/Homebrew.cs index 778e52fe54..90c6c4c641 100644 --- a/Ryujinx.HLE/OsHle/Homebrew.cs +++ b/Ryujinx.HLE/OsHle/Homebrew.cs @@ -10,23 +10,23 @@ namespace Ryujinx.HLE.OsHle //http://switchbrew.org/index.php?title=Homebrew_ABI public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle, string SwitchPath) { - Memory.Manager.Map(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW); - - //MainThreadHandle + //MainThreadHandle. WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle); - //NextLoadPath + //NextLoadPath. WriteConfigEntry(Memory, ref Position, 2, 0, Position + 0x200, Position + 0x400); - // Argv + //Argv. long ArgvPosition = Position + 0xC00; - WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition); + Memory.WriteBytes(ArgvPosition, Encoding.ASCII.GetBytes(SwitchPath + "\0")); - //AppletType + WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition); + + //AppletType. WriteConfigEntry(Memory, ref Position, 7); - //EndOfList + //EndOfList. WriteConfigEntry(Memory, ref Position, 0); } diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index b4c7d36eaf..d8dbb9caff 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -12,7 +12,7 @@ namespace Ryujinx.HLE.OsHle public class Horizon : IDisposable { internal const int HidSize = 0x40000; - internal const int FontSize = 0x50; + internal const int FontSize = 0x1100000; private Switch Ns; @@ -22,10 +22,8 @@ namespace Ryujinx.HLE.OsHle public SystemStateMgr SystemState { get; private set; } - internal MemoryAllocator Allocator { get; private set; } - - internal HSharedMem HidSharedMem { get; private set; } - internal HSharedMem FontSharedMem { get; private set; } + internal KSharedMemory HidSharedMem { get; private set; } + internal KSharedMemory FontSharedMem { get; private set; } internal KEvent VsyncEvent { get; private set; } @@ -39,10 +37,14 @@ namespace Ryujinx.HLE.OsHle SystemState = new SystemStateMgr(); - Allocator = new MemoryAllocator(); + if (!Ns.Memory.Allocator.TryAllocate(HidSize, out long HidPA) || + !Ns.Memory.Allocator.TryAllocate(FontSize, out long FontPA)) + { + throw new InvalidOperationException(); + } - HidSharedMem = new HSharedMem(); - FontSharedMem = new HSharedMem(); + HidSharedMem = new KSharedMemory(HidPA, HidSize); + FontSharedMem = new KSharedMemory(FontPA, FontSize); VsyncEvent = new KEvent(); } diff --git a/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs b/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs index bbae532555..a62fc1bfef 100644 --- a/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs +++ b/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs @@ -2,18 +2,21 @@ namespace Ryujinx.HLE.OsHle.Kernel { static class KernelErr { - public const int InvalidAlignment = 102; - public const int InvalidAddress = 106; - public const int InvalidMemRange = 110; - public const int InvalidPriority = 112; - public const int InvalidCoreId = 113; - public const int InvalidHandle = 114; - public const int InvalidCoreMask = 116; - public const int Timeout = 117; - public const int Canceled = 118; - public const int CountOutOfRange = 119; - public const int InvalidEnumValue = 120; - public const int InvalidThread = 122; - public const int InvalidState = 125; + public const int InvalidSize = 101; + public const int InvalidAddress = 102; + public const int OutOfMemory = 104; + public const int NoAccessPerm = 106; + public const int InvalidPermission = 108; + public const int InvalidMemRange = 110; + public const int InvalidPriority = 112; + public const int InvalidCoreId = 113; + public const int InvalidHandle = 114; + public const int InvalidMaskValue = 116; + public const int Timeout = 117; + public const int Canceled = 118; + public const int CountOutOfRange = 119; + public const int InvalidEnumValue = 120; + public const int InvalidThread = 122; + public const int InvalidState = 125; } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs index 6f7bc42fd7..d11cf72a39 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs @@ -10,7 +10,7 @@ using System.Threading; namespace Ryujinx.HLE.OsHle.Kernel { - partial class SvcHandler : IDisposable + partial class SvcHandler { private delegate void SvcFunc(AThreadState ThreadState); @@ -22,10 +22,6 @@ namespace Ryujinx.HLE.OsHle.Kernel private ConcurrentDictionary SyncWaits; - private HashSet<(HSharedMem, long, long)> MappedSharedMems; - - private ulong CurrentHeapSize; - private const uint SelfThreadHandle = 0xffff8000; private const uint SelfProcessHandle = 0xffff8001; @@ -70,8 +66,8 @@ namespace Ryujinx.HLE.OsHle.Kernel { 0x26, SvcBreak }, { 0x27, SvcOutputDebugString }, { 0x29, SvcGetInfo }, - { 0x2c, SvcMapPhysicalMemory }, - { 0x2d, SvcUnmapPhysicalMemory }, + //{ 0x2c, SvcMapPhysicalMemory }, + //{ 0x2d, SvcUnmapPhysicalMemory }, { 0x32, SvcSetThreadActivity }, { 0x33, SvcGetThreadContext3 }, { 0x34, SvcWaitForAddress } @@ -82,8 +78,6 @@ namespace Ryujinx.HLE.OsHle.Kernel this.Memory = Process.Memory; SyncWaits = new ConcurrentDictionary(); - - MappedSharedMems = new HashSet<(HSharedMem, long, long)>(); } static SvcHandler() @@ -126,26 +120,5 @@ namespace Ryujinx.HLE.OsHle.Kernel return Process.HandleTable.GetData(Handle); } } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - lock (MappedSharedMems) - { - foreach ((HSharedMem SharedMem, long Position, long Size) in MappedSharedMems) - { - SharedMem.RemoveVirtualPosition(Memory, Position, Size); - } - - MappedSharedMems.Clear(); - } - } - } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs index f10cad7a20..09c2d046c8 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs @@ -13,41 +13,83 @@ namespace Ryujinx.HLE.OsHle.Kernel { uint Size = (uint)ThreadState.X1; - long Position = MemoryRegions.HeapRegionAddress; - - if (Size > CurrentHeapSize) + if ((Size & 0x1fffff) != 0) { - Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + long Result = Process.MemoryManager.TrySetHeapSize(Size, out long Position); + + ThreadState.X0 = (ulong)Result; + + if (Result == 0) + { + ThreadState.X1 = (ulong)Position; } else { - Memory.Manager.Unmap(Position + Size, (long)CurrentHeapSize - Size); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); } - - CurrentHeapSize = Size; - - ThreadState.X0 = 0; - ThreadState.X1 = (ulong)Position; } private void SvcSetMemoryAttribute(AThreadState ThreadState) { long Position = (long)ThreadState.X0; long Size = (long)ThreadState.X1; - int State0 = (int)ThreadState.X2; - int State1 = (int)ThreadState.X3; - if ((State0 == 0 && State1 == 0) || - (State0 == 8 && State1 == 0)) + if (!PageAligned(Position)) { - Memory.Manager.ClearAttrBit(Position, Size, 3); - } - else if (State0 == 8 && State1 == 8) - { - Memory.Manager.SetAttrBit(Position, Size, 3); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; } - ThreadState.X0 = 0; + if (!PageAligned(Size) || Size == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + MemoryAttribute AttributeMask = (MemoryAttribute)ThreadState.X2; + MemoryAttribute AttributeValue = (MemoryAttribute)ThreadState.X3; + + MemoryAttribute Attributes = AttributeMask | AttributeValue; + + if (Attributes != AttributeMask || + (Attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); + + return; + } + + long Result = Process.MemoryManager.SetMemoryAttribute( + Position, + Size, + AttributeMask, + AttributeValue); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + else + { + Memory.StopObservingRegion(Position, Size); + } + + ThreadState.X0 = (ulong)Result; } private void SvcMapMemory(AThreadState ThreadState) @@ -56,33 +98,50 @@ namespace Ryujinx.HLE.OsHle.Kernel long Src = (long)ThreadState.X1; long Size = (long)ThreadState.X2; - if (!IsValidPosition(Src)) + if (!PageAligned(Src | Dst)) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid src address {Src:x16}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if (!InsideAddrSpace(Src, Size) || Src == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideMapRegion(Dst, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); return; } - if (!IsValidMapPosition(Dst)) + long Result = Process.MemoryManager.Map(Src, Dst, Size); + + if (Result != 0) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid dst address {Dst:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); - - return; + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); } - AMemoryMapInfo SrcInfo = Memory.Manager.GetMapInfo(Src); - - Memory.Manager.Map(Dst, Size, (int)MemoryType.MappedMemory, SrcInfo.Perm); - - Memory.Manager.Reprotect(Src, Size, AMemoryPerm.None); - - Memory.Manager.SetAttrBit(Src, Size, 0); - - ThreadState.X0 = 0; + ThreadState.X0 = (ulong)Result; } private void SvcUnmapMemory(AThreadState ThreadState) @@ -91,33 +150,50 @@ namespace Ryujinx.HLE.OsHle.Kernel long Src = (long)ThreadState.X1; long Size = (long)ThreadState.X2; - if (!IsValidPosition(Src)) + if (!PageAligned(Src | Dst)) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid src address {Src:x16}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; + } + + if (!PageAligned(Size) || Size == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if (!InsideAddrSpace(Src, Size) || Src == 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideMapRegion(Dst, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); return; } - if (!IsValidMapPosition(Dst)) + long Result = Process.MemoryManager.Unmap(Src, Dst, Size); + + if (Result != 0) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid dst address {Dst:x16}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); - - return; + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); } - AMemoryMapInfo DstInfo = Memory.Manager.GetMapInfo(Dst); - - Memory.Manager.Unmap(Dst, Size, (int)MemoryType.MappedMemory); - - Memory.Manager.Reprotect(Src, Size, DstInfo.Perm); - - Memory.Manager.ClearAttrBit(Src, Size, 0); - - ThreadState.X0 = 0; + ThreadState.X0 = (ulong)Result; } private void SvcQueryMemory(AThreadState ThreadState) @@ -125,26 +201,16 @@ namespace Ryujinx.HLE.OsHle.Kernel long InfoPtr = (long)ThreadState.X0; long Position = (long)ThreadState.X2; - AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); + KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position); - if (MapInfo == null) - { - long AddrSpaceEnd = MemoryRegions.AddrSpaceStart + MemoryRegions.AddrSpaceSize; - - long ReservedSize = (long)(ulong.MaxValue - (ulong)AddrSpaceEnd) + 1; - - MapInfo = new AMemoryMapInfo(AddrSpaceEnd, ReservedSize, (int)MemoryType.Reserved, 0, AMemoryPerm.None); - } - - Memory.WriteInt64(InfoPtr + 0x00, MapInfo.Position); - Memory.WriteInt64(InfoPtr + 0x08, MapInfo.Size); - Memory.WriteInt32(InfoPtr + 0x10, MapInfo.Type); - Memory.WriteInt32(InfoPtr + 0x14, MapInfo.Attr); - Memory.WriteInt32(InfoPtr + 0x18, (int)MapInfo.Perm); - Memory.WriteInt32(InfoPtr + 0x1c, 0); - Memory.WriteInt32(InfoPtr + 0x20, 0); + Memory.WriteInt64(InfoPtr + 0x00, BlkInfo.Position); + Memory.WriteInt64(InfoPtr + 0x08, BlkInfo.Size); + Memory.WriteInt32(InfoPtr + 0x10, (int)BlkInfo.State & 0xff); + Memory.WriteInt32(InfoPtr + 0x14, (int)BlkInfo.Attribute); + Memory.WriteInt32(InfoPtr + 0x18, (int)BlkInfo.Permission); + Memory.WriteInt32(InfoPtr + 0x1c, BlkInfo.IpcRefCount); + Memory.WriteInt32(InfoPtr + 0x20, BlkInfo.DeviceRefCount); Memory.WriteInt32(InfoPtr + 0x24, 0); - //TODO: X1. ThreadState.X0 = 0; ThreadState.X1 = 0; @@ -152,84 +218,140 @@ namespace Ryujinx.HLE.OsHle.Kernel private void SvcMapSharedMemory(AThreadState ThreadState) { - int Handle = (int)ThreadState.X0; - long Src = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - int Perm = (int)ThreadState.X3; + int Handle = (int)ThreadState.X0; + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; - if (!IsValidPosition(Src)) + if (!PageAligned(Position)) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Src:x16}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } - HSharedMem SharedMem = Process.HandleTable.GetData(Handle); - - if (SharedMem != null) + if (!PageAligned(Size) || Size == 0) { - Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, AMemoryPerm.Write); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - AMemoryHelper.FillWithZeros(Memory, Src, (int)Size); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - SharedMem.AddVirtualPosition(Memory, Src, Size); - - Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm); - - lock (MappedSharedMems) - { - MappedSharedMems.Add((SharedMem, Src, Size)); - } - - ThreadState.X0 = 0; + return; } - //TODO: Error codes. + MemoryPermission Permission = (MemoryPermission)ThreadState.X3; + + if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); + + return; + } + + KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); + + if (SharedMemory == null) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (!InsideAddrSpace(Position, Size) /*|| InsideMapRegion(Position, Size)*/ || InsideHeapRegion(Position, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (SharedMemory.Size != Size) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + long Result = Process.MemoryManager.MapSharedMemory(SharedMemory, Permission, Position); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; } private void SvcUnmapSharedMemory(AThreadState ThreadState) { - int Handle = (int)ThreadState.X0; - long Src = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; + int Handle = (int)ThreadState.X0; + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; - if (!IsValidPosition(Src)) + if (!PageAligned(Position)) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Src:x16}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } - HSharedMem SharedMem = Process.HandleTable.GetData(Handle); - - if (SharedMem != null) + if (!PageAligned(Size) || Size == 0) { - Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - SharedMem.RemoveVirtualPosition(Memory, Src, Size); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); - lock (MappedSharedMems) - { - MappedSharedMems.Remove((SharedMem, Src, Size)); - } - - ThreadState.X0 = 0; + return; } - //TODO: Error codes. + KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); + + if (SharedMemory == null) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + if (!InsideAddrSpace(Position, Size) /*|| InsideMapRegion(Position, Size)*/ || InsideHeapRegion(Position, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + long Result = Process.MemoryManager.UnmapSharedMemory(Position, Size); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; } private void SvcCreateTransferMemory(AThreadState ThreadState) { long Src = (long)ThreadState.X1; long Size = (long)ThreadState.X2; - int Perm = (int)ThreadState.X3; - if (!IsValidPosition(Src)) + MemoryPermission Permission = (MemoryPermission)ThreadState.X3; + + if (!InsideAddrSpace(Src, Size)) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Src:x16}!"); @@ -238,48 +360,56 @@ namespace Ryujinx.HLE.OsHle.Kernel return; } - AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Src); + Process.MemoryManager.ReserveTransferMemory(Src, Size, Permission); - Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm); + KTransferMemory TransferMemory = new KTransferMemory(Src, Size); - HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size); - - ulong Handle = (ulong)Process.HandleTable.OpenHandle(TMem); + int Handle = Process.HandleTable.OpenHandle(TransferMemory); ThreadState.X0 = 0; - ThreadState.X1 = Handle; + ThreadState.X1 = (ulong)Handle; } private void SvcMapPhysicalMemory(AThreadState ThreadState) { - long Position = (long)ThreadState.X0; - uint Size = (uint)ThreadState.X1; - - Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW); - - ThreadState.X0 = 0; + //TODO. } private void SvcUnmapPhysicalMemory(AThreadState ThreadState) { - long Position = (long)ThreadState.X0; - uint Size = (uint)ThreadState.X1; - - Memory.Manager.Unmap(Position, Size); - - ThreadState.X0 = 0; + //TODO. } - private static bool IsValidPosition(long Position) + private static bool PageAligned(long Position) { - return Position >= MemoryRegions.AddrSpaceStart && - Position < MemoryRegions.AddrSpaceStart + MemoryRegions.AddrSpaceSize; + return (Position & (KMemoryManager.PageSize - 1)) == 0; } - private static bool IsValidMapPosition(long Position) + private bool InsideAddrSpace(long Position, long Size) { - return Position >= MemoryRegions.MapRegionAddress && - Position < MemoryRegions.MapRegionAddress + MemoryRegions.MapRegionSize; + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.AddrSpaceStart && + End < (ulong)Process.MemoryManager.AddrSpaceEnd; + } + + private bool InsideMapRegion(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= MemoryRegions.MapRegionAddress && + End < MemoryRegions.MapRegionAddress + MemoryRegions.MapRegionSize; + } + + private bool InsideHeapRegion(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.HeapRegionStart && + End < (ulong)Process.MemoryManager.HeapRegionEnd; } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs index 08305522f5..04d527028c 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs @@ -53,12 +53,11 @@ namespace Ryujinx.HLE.OsHle.Kernel { Session.Dispose(); } - else if (Obj is HTransferMem TMem) + else if (Obj is KTransferMemory TransferMemory) { - TMem.Memory.Manager.Reprotect( - TMem.Position, - TMem.Size, - TMem.Perm); + Process.MemoryManager.ResetTransferMemory( + TransferMemory.Position, + TransferMemory.Size); } ThreadState.X0 = 0; @@ -326,7 +325,7 @@ namespace Ryujinx.HLE.OsHle.Kernel break; case 7: - ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize; + ThreadState.X1 = MemoryRegions.TotalMemoryUsed + (ulong)Process.MemoryManager.GetHeapSize(); break; case 8: diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs b/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs index 8702203e4e..0452485045 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs @@ -204,7 +204,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreMask); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); return; } @@ -226,7 +226,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreMask); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue); return; } diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs index 9fc426176c..164a85cac4 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs @@ -26,7 +26,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } @@ -35,7 +35,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } @@ -79,7 +79,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } @@ -88,7 +88,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } @@ -115,7 +115,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } @@ -124,7 +124,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } @@ -214,7 +214,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } @@ -223,7 +223,7 @@ namespace Ryujinx.HLE.OsHle.Kernel { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } diff --git a/Ryujinx.HLE/OsHle/MemoryAllocator.cs b/Ryujinx.HLE/OsHle/MemoryAllocator.cs deleted file mode 100644 index 8696aa4d11..0000000000 --- a/Ryujinx.HLE/OsHle/MemoryAllocator.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Ryujinx.HLE.OsHle -{ - class MemoryAllocator - { - public bool TryAllocate(long Size, out long Address) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/MemoryRegions.cs b/Ryujinx.HLE/OsHle/MemoryRegions.cs index 198c621ccc..2099945fbe 100644 --- a/Ryujinx.HLE/OsHle/MemoryRegions.cs +++ b/Ryujinx.HLE/OsHle/MemoryRegions.cs @@ -14,7 +14,7 @@ namespace Ryujinx.HLE.OsHle public const long MainStackSize = 0x100000; - public const long MainStackAddress = AMemoryMgr.AddrSize - MainStackSize; + public const long MainStackAddress = 0x100000000L - MainStackSize; public const long TlsPagesSize = 0x20000; @@ -22,8 +22,8 @@ namespace Ryujinx.HLE.OsHle public const long TotalMemoryUsed = HeapRegionAddress + TlsPagesSize + MainStackSize; - public const long TotalMemoryAvailable = AMemoryMgr.RamSize - AddrSpaceStart; + public const long TotalMemoryAvailable = 0x100000000L - AddrSpaceStart; - public const long AddrSpaceSize = AMemoryMgr.AddrSize - AddrSpaceStart; + public const long AddrSpaceSize = 0x100000000L - AddrSpaceStart; } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs index 6cbc086045..ddb69f7d4d 100644 --- a/Ryujinx.HLE/OsHle/Process.cs +++ b/Ryujinx.HLE/OsHle/Process.cs @@ -40,6 +40,8 @@ namespace Ryujinx.HLE.OsHle public AMemory Memory { get; private set; } + public KMemoryManager MemoryManager { get; private set; } + public KProcessScheduler Scheduler { get; private set; } public List ThreadArbiterList { get; private set; } @@ -76,7 +78,9 @@ namespace Ryujinx.HLE.OsHle this.Scheduler = Scheduler; this.ProcessId = ProcessId; - Memory = new AMemory(); + Memory = new AMemory(Ns.Memory.RamPointer); + + MemoryManager = new KMemoryManager(Memory, Ns.Memory.Allocator); ThreadArbiterList = new List(); @@ -96,10 +100,11 @@ namespace Ryujinx.HLE.OsHle ImageBase = MemoryRegions.AddrSpaceStart; - MapRWMemRegion( + MemoryManager.HleMapCustom( MemoryRegions.TlsPagesAddress, MemoryRegions.TlsPagesSize, - MemoryType.ThreadLocal); + MemoryState.ThreadLocal, + MemoryPermission.ReadAndWrite); } public void LoadProgram(IExecutable Program) @@ -111,17 +116,17 @@ namespace Ryujinx.HLE.OsHle Ns.Log.PrintInfo(LogClass.Loader, $"Image base at 0x{ImageBase:x16}."); - Executable Executable = new Executable(Program, Memory, ImageBase); + Executable Executable = new Executable(Program, MemoryManager, Memory, ImageBase); Executables.Add(Executable); - ImageBase = AMemoryHelper.PageRoundUp(Executable.ImageEnd); + ImageBase = IntUtils.AlignUp(Executable.ImageEnd, KMemoryManager.PageSize); } public void SetEmptyArgs() { //TODO: This should be part of Run. - ImageBase += AMemoryMgr.PageSize; + ImageBase += KMemoryManager.PageSize; } public bool Run(bool NeedsHbAbi = false) @@ -140,10 +145,11 @@ namespace Ryujinx.HLE.OsHle MakeSymbolTable(); - MapRWMemRegion( + MemoryManager.HleMapCustom( MemoryRegions.MainStackAddress, MemoryRegions.MainStackSize, - MemoryType.Normal); + MemoryState.MappedMemory, + MemoryPermission.ReadAndWrite); long StackTop = MemoryRegions.MainStackAddress + MemoryRegions.MainStackSize; @@ -158,7 +164,15 @@ namespace Ryujinx.HLE.OsHle if (NeedsHbAbi) { - HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd); + HbAbiDataPosition = IntUtils.AlignUp(Executables[0].ImageEnd, KMemoryManager.PageSize); + + const long HbAbiDataSize = KMemoryManager.PageSize; + + MemoryManager.HleMapCustom( + HbAbiDataPosition, + HbAbiDataSize, + MemoryState.MappedMemory, + MemoryPermission.ReadAndWrite); string SwitchPath = Ns.VFs.SystemPathToSwitchPath(Executables[0].FilePath); @@ -173,11 +187,6 @@ namespace Ryujinx.HLE.OsHle return true; } - private void MapRWMemRegion(long Position, long Size, MemoryType Type) - { - Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW); - } - public void StopAllThreadsAsync() { if (Disposed) @@ -439,10 +448,6 @@ namespace Ryujinx.HLE.OsHle AppletState.Dispose(); - SvcHandler.Dispose(); - - Memory.Dispose(); - Ns.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting..."); } } diff --git a/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs index 2ef67cc3a7..5c32ca837d 100644 --- a/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs +++ b/Ryujinx.HLE/OsHle/Services/Hid/IAppletResource.cs @@ -10,9 +10,9 @@ namespace Ryujinx.HLE.OsHle.Services.Hid public override IReadOnlyDictionary Commands => m_Commands; - private HSharedMem HidSharedMem; + private KSharedMemory HidSharedMem; - public IAppletResource(HSharedMem HidSharedMem) + public IAppletResource(KSharedMemory HidSharedMem) { m_Commands = new Dictionary() { diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs index 7705a1f78f..7f20345381 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvHostCtrl/NvHostCtrlIoctl.cs @@ -120,7 +120,7 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvHostCtrl Context.Ns.Log.PrintDebug(Logging.LogClass.ServiceNv, $"Got setting {Domain}!{Name}"); } - + return NvResult.Success; } diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs index 1e13f19746..bc66fc7173 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapFree.cs @@ -4,7 +4,7 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap { public int Handle; public int Padding; - public long RefCount; + public long Address; public int Size; public int Flags; } diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs index 21fce700c3..f349a03ef6 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapHandle.cs @@ -31,7 +31,7 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap public long DecrementRefCount() { - return Interlocked.Decrement(ref Dupes) + 1; + return Interlocked.Decrement(ref Dupes); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs index 4c6107f8f8..e5b2982590 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs @@ -129,7 +129,8 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap { //When the address is zero, we need to allocate //our own backing memory for the NvMap. - if (!Context.Ns.Os.Allocator.TryAllocate((uint)Size, out Address)) + //TODO: Is this allocation inside the transfer memory? + if (!Context.Ns.Memory.Allocator.TryAllocate((uint)Size, out Address)) { Result = NvResult.OutOfMemory; } @@ -163,23 +164,22 @@ namespace Ryujinx.HLE.OsHle.Services.Nv.NvMap return NvResult.InvalidInput; } - long OldRefCount = Map.DecrementRefCount(); - - if (OldRefCount <= 1) + if (Map.DecrementRefCount() <= 0) { DeleteNvMap(Context, Args.Handle); Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!"); - Args.Flags = 0; + Args.Address = Map.Address; + Args.Flags = 0; } else { - Args.Flags = FlagNotFreedYet; + Args.Address = 0; + Args.Flags = FlagNotFreedYet; } - Args.RefCount = OldRefCount; - Args.Size = Map.Size; + Args.Size = Map.Size; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); diff --git a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs index 41f2916f4a..04b50bb350 100644 --- a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs @@ -159,7 +159,7 @@ namespace Ryujinx.HLE.OsHle.Services.Android int Slot = GetFreeSlotBlocking(Width, Height); - return MakeReplyParcel(Context, Slot, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + return MakeReplyParcel(Context, Slot, 1, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader) diff --git a/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs b/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs index 39cced280a..010dbb20d1 100644 --- a/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs +++ b/Ryujinx.HLE/OsHle/Utilities/IntUtils.cs @@ -11,5 +11,15 @@ namespace Ryujinx.HLE.OsHle.Utilities { return (Value + (Size - 1)) & ~((long)Size - 1); } + + public static int AlignDown(int Value, int Size) + { + return Value & ~(Size - 1); + } + + public static long AlignDown(long Value, int Size) + { + return Value & ~((long)Size - 1); + } } } diff --git a/Ryujinx.HLE/PerformanceStatistics.cs b/Ryujinx.HLE/PerformanceStatistics.cs index 9bc3d6b477..2dabd9a08d 100644 --- a/Ryujinx.HLE/PerformanceStatistics.cs +++ b/Ryujinx.HLE/PerformanceStatistics.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.Timers; - namespace Ryujinx.HLE { public class PerformanceStatistics diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 475e511604..a11d584695 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -4,6 +4,7 @@ using Ryujinx.HLE.Font; using Ryujinx.HLE.Gpu; using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Memory; using Ryujinx.HLE.OsHle; using System; @@ -15,6 +16,8 @@ namespace Ryujinx.HLE public Logger Log { get; private set; } + internal DeviceMemory Memory { get; private set; } + internal NvGpu Gpu { get; private set; } internal VirtualFileSystem VFs { get; private set; } @@ -45,6 +48,8 @@ namespace Ryujinx.HLE Log = new Logger(); + Memory = new DeviceMemory(); + Gpu = new NvGpu(Renderer); VFs = new VirtualFileSystem(); @@ -53,15 +58,7 @@ namespace Ryujinx.HLE Statistics = new PerformanceStatistics(); - Hid = new Hid(Log); - - Font = new SharedFontManager(Log, VFs.GetSystemPath()); - - Os.HidSharedMem.MemoryMapped += Hid.ShMemMap; - Os.HidSharedMem.MemoryUnmapped += Hid.ShMemUnmap; - - Os.FontSharedMem.MemoryMapped += Font.ShMemMap; - Os.FontSharedMem.MemoryUnmapped += Font.ShMemUnmap; + Hid = new Hid(this, Os.HidSharedMem.PA); } public void LoadCart(string ExeFsDir, string RomFsFile = null) diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 70a8e19240..e6a0237987 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -5,6 +5,7 @@ using ChocolArm64.State; using NUnit.Framework; using System; +using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using System.Threading; @@ -19,6 +20,8 @@ namespace Ryujinx.Tests.Cpu private long EntryPoint; + private IntPtr RamPointer; + private AMemory Memory; private AThread Thread; @@ -31,15 +34,16 @@ namespace Ryujinx.Tests.Cpu EntryPoint = Position; ATranslator Translator = new ATranslator(); - Memory = new AMemory(); - Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute); + RamPointer = Marshal.AllocHGlobal(new IntPtr(Size)); + Memory = new AMemory(RamPointer); + Memory.Map(Position, 0, Size); Thread = new AThread(Translator, Memory, EntryPoint); } [TearDown] public void Teardown() { - Memory.Dispose(); + Marshal.FreeHGlobal(RamPointer); Memory = null; Thread = null; } @@ -52,7 +56,7 @@ namespace Ryujinx.Tests.Cpu protected void Opcode(uint Opcode) { - Thread.Memory.WriteUInt32Unchecked(Position, Opcode); + Thread.Memory.WriteUInt32(Position, Opcode); Position += 4; } diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs index 145427068b..ec0f05b799 100644 --- a/Ryujinx/Config.cs +++ b/Ryujinx/Config.cs @@ -23,8 +23,6 @@ namespace Ryujinx IniParser Parser = new IniParser(IniPath); - AOptimizations.DisableMemoryChecks = !Convert.ToBoolean(Parser.Value("Enable_Memory_Checks")); - GraphicsConfig.ShadersDumpPath = Parser.Value("Graphics_Shaders_Dump_Path"); Device.Log.SetEnable(LogLevel.Debug, Convert.ToBoolean(Parser.Value("Logging_Enable_Debug")));