diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-08-15 15:59:51 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-15 15:59:51 -0300 |
| commit | c393cdf8e3775bc95850e4d8c8e4c446b286d3b4 (patch) | |
| tree | 25035a244741d2daf3f7d6be8b23153ff061ea15 /Ryujinx.HLE/OsHle/Kernel | |
| parent | 76d95dee05e3c51c18e1799f54cc407e0f633b4e (diff) | |
More flexible memory manager (#307)
* Keep track mapped buffers with fixed offsets
* Started rewriting the memory manager
* Initial support for MapPhysicalMemory and UnmapPhysicalMemory, other tweaks
* MapPhysicalMemory/UnmapPhysicalMemory support, other tweaks
* Rebased
* Optimize the map/unmap physical memory svcs
* Integrate shared font support
* Fix address space reserve alignment
* Some fixes related to gpu memory mapping
* Some cleanup
* Only try uploading const buffers that are really used
* Check if memory region is contiguous
* Rebased
* Add missing count increment on IsRegionModified
* Check for reads/writes outside of the address space, optimize translation with a tail call
Diffstat (limited to 'Ryujinx.HLE/OsHle/Kernel')
| -rw-r--r-- | Ryujinx.HLE/OsHle/Kernel/KernelErr.cs | 29 | ||||
| -rw-r--r-- | Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs | 29 | ||||
| -rw-r--r-- | Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs | 527 | ||||
| -rw-r--r-- | Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs | 41 | ||||
| -rw-r--r-- | Ryujinx.HLE/OsHle/Kernel/SvcThread.cs | 4 | ||||
| -rw-r--r-- | Ryujinx.HLE/OsHle/Kernel/SvcThreadSync.cs | 16 |
6 files changed, 460 insertions, 186 deletions
diff --git a/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs b/Ryujinx.HLE/OsHle/Kernel/KernelErr.cs index bbae5325..a62fc1bf 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 6f7bc42f..a33ffe5e 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<KThread, AutoResetEvent> SyncWaits; - private HashSet<(HSharedMem, long, long)> MappedSharedMems; - - private ulong CurrentHeapSize; - private const uint SelfThreadHandle = 0xffff8000; private const uint SelfProcessHandle = 0xffff8001; @@ -82,8 +78,6 @@ namespace Ryujinx.HLE.OsHle.Kernel this.Memory = Process.Memory; SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>(); - - MappedSharedMems = new HashSet<(HSharedMem, long, long)>(); } static SvcHandler() @@ -126,26 +120,5 @@ namespace Ryujinx.HLE.OsHle.Kernel return Process.HandleTable.GetData<KThread>(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 f10cad7a..68d87293 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs @@ -1,4 +1,3 @@ -using ChocolArm64.Memory; using ChocolArm64.State; using Ryujinx.HLE.Logging; using Ryujinx.HLE.OsHle.Handles; @@ -11,43 +10,85 @@ namespace Ryujinx.HLE.OsHle.Kernel { private void SvcSetHeapSize(AThreadState ThreadState) { - uint Size = (uint)ThreadState.X1; + long Size = (long)ThreadState.X1; - long Position = MemoryRegions.HeapRegionAddress; + if ((Size & 0x1fffff) != 0 || Size != (uint)Size) + { + 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); - if (Size > CurrentHeapSize) + ThreadState.X0 = (ulong)Result; + + if (Result == 0) { - Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW); + 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); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); + + return; } - else if (State0 == 8 && State1 == 8) + + if (!PageAligned(Size) || Size == 0) { - Memory.Manager.SetAttrBit(Position, Size, 3); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; } - ThreadState.X0 = 0; + 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 +97,59 @@ 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.InvalidMemRange); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } - if (!IsValidMapPosition(Dst)) + if (!PageAligned(Size) || Size == 0) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid dst address {Dst:x16}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); return; } - AMemoryMapInfo SrcInfo = Memory.Manager.GetMapInfo(Src); + if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); - Memory.Manager.Map(Dst, Size, (int)MemoryType.MappedMemory, SrcInfo.Perm); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - Memory.Manager.Reprotect(Src, Size, AMemoryPerm.None); + return; + } + + if (!InsideAddrSpace(Src, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); - Memory.Manager.SetAttrBit(Src, Size, 0); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - ThreadState.X0 = 0; + return; + } + + if (!InsideNewMapRegion(Dst, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + + return; + } + + long Result = Process.MemoryManager.Map(Src, Dst, Size); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; } private void SvcUnmapMemory(AThreadState ThreadState) @@ -91,33 +158,59 @@ 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.InvalidMemRange); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } - if (!IsValidMapPosition(Dst)) + if (!PageAligned(Size) || Size == 0) { - Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid dst address {Dst:x16}!"); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); + + return; + } + + if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } - AMemoryMapInfo DstInfo = Memory.Manager.GetMapInfo(Dst); + if (!InsideAddrSpace(Src, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!"); - Memory.Manager.Unmap(Dst, Size, (int)MemoryType.MappedMemory); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - Memory.Manager.Reprotect(Src, Size, DstInfo.Perm); + return; + } - Memory.Manager.ClearAttrBit(Src, Size, 0); + if (!InsideNewMapRegion(Dst, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!"); - ThreadState.X0 = 0; + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange); + + return; + } + + long Result = Process.MemoryManager.Unmap(Src, Dst, Size); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; } private void SvcQueryMemory(AThreadState ThreadState) @@ -125,26 +218,16 @@ namespace Ryujinx.HLE.OsHle.Kernel long InfoPtr = (long)ThreadState.X0; long Position = (long)ThreadState.X2; - AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); - - if (MapInfo == null) - { - long AddrSpaceEnd = MemoryRegions.AddrSpaceStart + MemoryRegions.AddrSpaceSize; - - long ReservedSize = (long)(ulong.MaxValue - (ulong)AddrSpaceEnd) + 1; + KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position); - 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,134 +235,344 @@ 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; + } + + 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 ((ulong)(Position + Size) <= (ulong)Position) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } - HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle); + MemoryPermission Permission = (MemoryPermission)ThreadState.X3; - if (SharedMem != null) + if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) { - Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, AMemoryPerm.Write); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); - AMemoryHelper.FillWithZeros(Memory, Src, (int)Size); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); - SharedMem.AddVirtualPosition(Memory, Src, Size); + return; + } - Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm); + KSharedMemory SharedMemory = Process.HandleTable.GetData<KSharedMemory>(Handle); + + if (SharedMemory == null) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); - lock (MappedSharedMems) - { - MappedSharedMems.Add((SharedMem, Src, Size)); - } + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } - ThreadState.X0 = 0; + 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}!"); } - //TODO: Error codes. + 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<HSharedMem>(Handle); + 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 (SharedMem != null) + if ((ulong)(Position + Size) <= (ulong)Position) { - Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory); + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); - SharedMem.RemoveVirtualPosition(Memory, Src, Size); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); - lock (MappedSharedMems) - { - MappedSharedMems.Remove((SharedMem, Src, Size)); - } + return; + } - ThreadState.X0 = 0; + KSharedMemory SharedMemory = Process.HandleTable.GetData<KSharedMemory>(Handle); + + if (SharedMemory == null) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; } - //TODO: Error codes. + 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; + 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; + } + + 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.InvalidAddress); return; } - AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Src); + if ((ulong)(Position + Size) <= (ulong)Position) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + MemoryPermission Permission = (MemoryPermission)ThreadState.X3; + + if (Permission > MemoryPermission.ReadAndWrite || Permission == MemoryPermission.Write) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission); + + return; + } - Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm); + Process.MemoryManager.ReserveTransferMemory(Position, Size, Permission); - HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size); + KTransferMemory TransferMemory = new KTransferMemory(Position, 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; + long Size = (long)ThreadState.X1; + + if (!PageAligned(Position)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - ThreadState.X0 = 0; + 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 ((ulong)(Position + Size) <= (ulong)Position) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideAddrSpace(Position, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + long Result = Process.MemoryManager.MapPhysicalMemory(Position, Size); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; } private void SvcUnmapPhysicalMemory(AThreadState ThreadState) { long Position = (long)ThreadState.X0; - uint Size = (uint)ThreadState.X1; + long Size = (long)ThreadState.X1; + + if (!PageAligned(Position)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); - Memory.Manager.Unmap(Position, Size); + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); - ThreadState.X0 = 0; + 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 ((ulong)(Position + Size) <= (ulong)Position) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + if (!InsideAddrSpace(Position, Size)) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); + + return; + } + + long Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size); + + if (Result != 0) + { + Ns.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); + } + + ThreadState.X0 = (ulong)Result; + } + + private static bool PageAligned(long Position) + { + return (Position & (KMemoryManager.PageSize - 1)) == 0; + } + + private bool InsideAddrSpace(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.AddrSpaceStart && + End < (ulong)Process.MemoryManager.AddrSpaceEnd; } - private static bool IsValidPosition(long Position) + private bool InsideMapRegion(long Position, long Size) { - return Position >= MemoryRegions.AddrSpaceStart && - Position < MemoryRegions.AddrSpaceStart + MemoryRegions.AddrSpaceSize; + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.MapRegionStart && + End < (ulong)Process.MemoryManager.MapRegionEnd; } - private static bool IsValidMapPosition(long Position) + private bool InsideHeapRegion(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.HeapRegionStart && + End < (ulong)Process.MemoryManager.HeapRegionEnd; + } + + private bool InsideNewMapRegion(long Position, long Size) + { + ulong Start = (ulong)Position; + ulong End = (ulong)Size + Start; + + return Start >= (ulong)Process.MemoryManager.NewMapRegionStart && + End < (ulong)Process.MemoryManager.NewMapRegionEnd; } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs index 08305522..f833745b 100644 --- a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs +++ b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs @@ -18,8 +18,6 @@ namespace Ryujinx.HLE.OsHle.Kernel private const bool EnableProcessDebugging = false; - private const bool IsVirtualMemoryEnabled = true; //This is always true(?) - private void SvcExitProcess(AThreadState ThreadState) { Ns.Os.ExitProcess(ThreadState.ProcessId); @@ -53,12 +51,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; @@ -306,27 +303,29 @@ namespace Ryujinx.HLE.OsHle.Kernel break; case 2: - ThreadState.X1 = MemoryRegions.MapRegionAddress; + ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionStart; break; case 3: - ThreadState.X1 = MemoryRegions.MapRegionSize; + ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionEnd - + (ulong)Process.MemoryManager.MapRegionStart; break; case 4: - ThreadState.X1 = MemoryRegions.HeapRegionAddress; + ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart; break; case 5: - ThreadState.X1 = MemoryRegions.HeapRegionSize; + ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd - + (ulong)Process.MemoryManager.HeapRegionStart; break; case 6: - ThreadState.X1 = MemoryRegions.TotalMemoryAvailable; + ThreadState.X1 = (ulong)Process.Ns.Memory.Allocator.TotalAvailableSize; break; case 7: - ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize; + ThreadState.X1 = (ulong)Process.Ns.Memory.Allocator.TotalUsedSize; break; case 8: @@ -338,23 +337,29 @@ namespace Ryujinx.HLE.OsHle.Kernel break; case 12: - ThreadState.X1 = MemoryRegions.AddrSpaceStart; + ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart; break; case 13: - ThreadState.X1 = MemoryRegions.AddrSpaceSize; + ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd - + (ulong)Process.MemoryManager.AddrSpaceStart; break; case 14: - ThreadState.X1 = MemoryRegions.MapRegionAddress; + ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionStart; break; case 15: - ThreadState.X1 = MemoryRegions.MapRegionSize; + ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionEnd - + (ulong)Process.MemoryManager.NewMapRegionStart; break; case 16: - ThreadState.X1 = IsVirtualMemoryEnabled ? 1 : 0; + ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0); + break; + + case 17: + ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage; break; default: diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs b/Ryujinx.HLE/OsHle/Kernel/SvcThread.cs index 8702203e..04524850 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 9fc42617..164a85ca 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; } |
