aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Kernel
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-06-10 21:46:42 -0300
committergdkchan <gab.dark.100@gmail.com>2018-06-10 21:46:42 -0300
commit76f3b1b3a4637ec72abfbb8cbc0679f2e0ca838f (patch)
tree0411b709de31c1c0517763512df8eeb9f7491bc9 /Ryujinx.Core/OsHle/Kernel
parent518fe799da6dd4f12c58c9e6e174767effb0b868 (diff)
Rename Ryujinx.Core to Ryujinx.HLE and add a separate project for a future LLE implementation
Diffstat (limited to 'Ryujinx.Core/OsHle/Kernel')
-rw-r--r--Ryujinx.Core/OsHle/Kernel/KernelErr.cs17
-rw-r--r--Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs19
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcHandler.cs147
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcMemory.cs285
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcSystem.cs369
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThread.cs291
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs435
7 files changed, 0 insertions, 1563 deletions
diff --git a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs b/Ryujinx.Core/OsHle/Kernel/KernelErr.cs
deleted file mode 100644
index 17c0044c..00000000
--- a/Ryujinx.Core/OsHle/Kernel/KernelErr.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Ryujinx.Core.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 InvalidInfo = 120;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs b/Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs
deleted file mode 100644
index 84fb0b85..00000000
--- a/Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace Ryujinx.Core.OsHle.Kernel
-{
- static class NsTimeConverter
- {
- public static int GetTimeMs(ulong Ns)
- {
- ulong Ms = Ns / 1_000_000;
-
- if (Ms < int.MaxValue)
- {
- return (int)Ms;
- }
- else
- {
- return int.MaxValue;
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
deleted file mode 100644
index 70ed3853..00000000
--- a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-using ChocolArm64.Events;
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using Ryujinx.Core.Logging;
-using Ryujinx.Core.OsHle.Handles;
-using System;
-using System.Collections.Generic;
-using System.Collections.Concurrent;
-using System.Threading;
-
-namespace Ryujinx.Core.OsHle.Kernel
-{
- partial class SvcHandler : IDisposable
- {
- private delegate void SvcFunc(AThreadState ThreadState);
-
- private Dictionary<int, SvcFunc> SvcFuncs;
-
- private Switch Ns;
- private Process Process;
- private AMemory Memory;
-
- private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits;
-
- private HashSet<(HSharedMem, long)> MappedSharedMems;
-
- private ulong CurrentHeapSize;
-
- private const uint SelfThreadHandle = 0xffff8000;
- private const uint SelfProcessHandle = 0xffff8001;
-
- private static Random Rng;
-
- public SvcHandler(Switch Ns, Process Process)
- {
- SvcFuncs = new Dictionary<int, SvcFunc>()
- {
- { 0x01, SvcSetHeapSize },
- { 0x03, SvcSetMemoryAttribute },
- { 0x04, SvcMapMemory },
- { 0x05, SvcUnmapMemory },
- { 0x06, SvcQueryMemory },
- { 0x07, SvcExitProcess },
- { 0x08, SvcCreateThread },
- { 0x09, SvcStartThread },
- { 0x0a, SvcExitThread },
- { 0x0b, SvcSleepThread },
- { 0x0c, SvcGetThreadPriority },
- { 0x0d, SvcSetThreadPriority },
- { 0x0e, SvcGetThreadCoreMask },
- { 0x0f, SvcSetThreadCoreMask },
- { 0x10, SvcGetCurrentProcessorNumber },
- { 0x12, SvcClearEvent },
- { 0x13, SvcMapSharedMemory },
- { 0x14, SvcUnmapSharedMemory },
- { 0x15, SvcCreateTransferMemory },
- { 0x16, SvcCloseHandle },
- { 0x17, SvcResetSignal },
- { 0x18, SvcWaitSynchronization },
- { 0x19, SvcCancelSynchronization },
- { 0x1a, SvcArbitrateLock },
- { 0x1b, SvcArbitrateUnlock },
- { 0x1c, SvcWaitProcessWideKeyAtomic },
- { 0x1d, SvcSignalProcessWideKey },
- { 0x1e, SvcGetSystemTick },
- { 0x1f, SvcConnectToNamedPort },
- { 0x21, SvcSendSyncRequest },
- { 0x22, SvcSendSyncRequestWithUserBuffer },
- { 0x25, SvcGetThreadId },
- { 0x26, SvcBreak },
- { 0x27, SvcOutputDebugString },
- { 0x29, SvcGetInfo },
- { 0x2c, SvcMapPhysicalMemory },
- { 0x2d, SvcUnmapPhysicalMemory },
- { 0x32, SvcSetThreadActivity }
- };
-
- this.Ns = Ns;
- this.Process = Process;
- this.Memory = Process.Memory;
-
- SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>();
-
- MappedSharedMems = new HashSet<(HSharedMem, long)>();
- }
-
- static SvcHandler()
- {
- Rng = new Random();
- }
-
- public void SvcCall(object sender, AInstExceptionEventArgs e)
- {
- AThreadState ThreadState = (AThreadState)sender;
-
- if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
- {
- Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
-
- Func(ThreadState);
-
- Process.Scheduler.Reschedule(Process.GetThread(ThreadState.Tpidr));
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended.");
- }
- else
- {
- Process.PrintStackTrace(ThreadState);
-
- throw new NotImplementedException(e.Id.ToString("x4"));
- }
- }
-
- private KThread GetThread(long Tpidr, int Handle)
- {
- if ((uint)Handle == SelfThreadHandle)
- {
- return Process.GetThread(Tpidr);
- }
- else
- {
- 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) in MappedSharedMems)
- {
- SharedMem.RemoveVirtualPosition(Memory, Position);
- }
-
- MappedSharedMems.Clear();
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcMemory.cs b/Ryujinx.Core/OsHle/Kernel/SvcMemory.cs
deleted file mode 100644
index 3e3cfab5..00000000
--- a/Ryujinx.Core/OsHle/Kernel/SvcMemory.cs
+++ /dev/null
@@ -1,285 +0,0 @@
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using Ryujinx.Core.Logging;
-using Ryujinx.Core.OsHle.Handles;
-
-using static Ryujinx.Core.OsHle.ErrorCode;
-
-namespace Ryujinx.Core.OsHle.Kernel
-{
- partial class SvcHandler
- {
- private void SvcSetHeapSize(AThreadState ThreadState)
- {
- uint Size = (uint)ThreadState.X1;
-
- long Position = MemoryRegions.HeapRegionAddress;
-
- if (Size > CurrentHeapSize)
- {
- Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW);
- }
- else
- {
- Memory.Manager.Unmap(Position + Size, (long)CurrentHeapSize - Size);
- }
-
- 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))
- {
- Memory.Manager.ClearAttrBit(Position, Size, 3);
- }
- else if (State0 == 8 && State1 == 8)
- {
- Memory.Manager.SetAttrBit(Position, Size, 3);
- }
-
- ThreadState.X0 = 0;
- }
-
- private void SvcMapMemory(AThreadState ThreadState)
- {
- long Dst = (long)ThreadState.X0;
- long Src = (long)ThreadState.X1;
- long Size = (long)ThreadState.X2;
-
- if (!IsValidPosition(Src))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid src address {Src:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- if (!IsValidMapPosition(Dst))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid dst address {Dst:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- 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;
- }
-
- private void SvcUnmapMemory(AThreadState ThreadState)
- {
- long Dst = (long)ThreadState.X0;
- long Src = (long)ThreadState.X1;
- long Size = (long)ThreadState.X2;
-
- if (!IsValidPosition(Src))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid src address {Src:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- if (!IsValidMapPosition(Dst))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid dst address {Dst:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- 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;
- }
-
- private void SvcQueryMemory(AThreadState ThreadState)
- {
- 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;
-
- 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.WriteInt32(InfoPtr + 0x24, 0);
- //TODO: X1.
-
- ThreadState.X0 = 0;
- ThreadState.X1 = 0;
- }
-
- 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;
-
- if (!IsValidPosition(Src))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Src:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
-
- if (SharedMem != null)
- {
- Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, AMemoryPerm.Write);
-
- AMemoryHelper.FillWithZeros(Memory, Src, (int)Size);
-
- Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
-
- lock (MappedSharedMems)
- {
- MappedSharedMems.Add((SharedMem, Src));
- }
-
- SharedMem.AddVirtualPosition(Memory, Src);
-
- ThreadState.X0 = 0;
- }
-
- //TODO: Error codes.
- }
-
- private void SvcUnmapSharedMemory(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
- long Src = (long)ThreadState.X1;
- long Size = (long)ThreadState.X2;
-
- if (!IsValidPosition(Src))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Src:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
-
- if (SharedMem != null)
- {
- Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory);
-
- SharedMem.RemoveVirtualPosition(Memory, Src);
-
- lock (MappedSharedMems)
- {
- MappedSharedMems.Remove((SharedMem, Src));
- }
-
- ThreadState.X0 = 0;
- }
-
- //TODO: Error codes.
- }
-
- private void SvcCreateTransferMemory(AThreadState ThreadState)
- {
- long Src = (long)ThreadState.X1;
- long Size = (long)ThreadState.X2;
- int Perm = (int)ThreadState.X3;
-
- if (!IsValidPosition(Src))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Src:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
-
- return;
- }
-
- AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Src);
-
- Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
-
- HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
-
- ulong Handle = (ulong)Process.HandleTable.OpenHandle(TMem);
-
- ThreadState.X0 = 0;
- ThreadState.X1 = 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;
- }
-
- private void SvcUnmapPhysicalMemory(AThreadState ThreadState)
- {
- long Position = (long)ThreadState.X0;
- uint Size = (uint)ThreadState.X1;
-
- Memory.Manager.Unmap(Position, Size);
-
- ThreadState.X0 = 0;
- }
-
- private static bool IsValidPosition(long Position)
- {
- return Position >= MemoryRegions.AddrSpaceStart &&
- Position < MemoryRegions.AddrSpaceStart + MemoryRegions.AddrSpaceSize;
- }
-
- private static bool IsValidMapPosition(long Position)
- {
- return Position >= MemoryRegions.MapRegionAddress &&
- Position < MemoryRegions.MapRegionAddress + MemoryRegions.MapRegionSize;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs
deleted file mode 100644
index 638625d8..00000000
--- a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs
+++ /dev/null
@@ -1,369 +0,0 @@
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using Ryujinx.Core.Logging;
-using Ryujinx.Core.OsHle.Exceptions;
-using Ryujinx.Core.OsHle.Handles;
-using Ryujinx.Core.OsHle.Ipc;
-using Ryujinx.Core.OsHle.Services;
-using System;
-using System.Threading;
-
-using static Ryujinx.Core.OsHle.ErrorCode;
-
-namespace Ryujinx.Core.OsHle.Kernel
-{
- partial class SvcHandler
- {
- private const int AllowedCpuIdBitmask = 0b1111;
-
- private const bool EnableProcessDebugging = false;
-
- private const bool IsVirtualMemoryEnabled = true; //This is always true(?)
-
- private void SvcExitProcess(AThreadState ThreadState)
- {
- Ns.Os.ExitProcess(ThreadState.ProcessId);
- }
-
- private void SvcClearEvent(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
-
- //TODO: Implement events.
-
- ThreadState.X0 = 0;
- }
-
- private void SvcCloseHandle(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
-
- object Obj = Process.HandleTable.CloseHandle(Handle);
-
- if (Obj == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- if (Obj is KSession Session)
- {
- Session.Dispose();
- }
- else if (Obj is HTransferMem TMem)
- {
- TMem.Memory.Manager.Reprotect(
- TMem.Position,
- TMem.Size,
- TMem.Perm);
- }
-
- ThreadState.X0 = 0;
- }
-
- private void SvcResetSignal(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
-
- KEvent Event = Process.HandleTable.GetData<KEvent>(Handle);
-
- if (Event != null)
- {
- Event.WaitEvent.Reset();
-
- ThreadState.X0 = 0;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid event handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcWaitSynchronization(AThreadState ThreadState)
- {
- long HandlesPtr = (long)ThreadState.X1;
- int HandlesCount = (int)ThreadState.X2;
- ulong Timeout = ThreadState.X3;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc,
- "HandlesPtr = " + HandlesPtr .ToString("x16") + ", " +
- "HandlesCount = " + HandlesCount.ToString("x8") + ", " +
- "Timeout = " + Timeout .ToString("x16"));
-
- if ((uint)HandlesCount > 0x40)
- {
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
-
- return;
- }
-
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- WaitHandle[] Handles = new WaitHandle[HandlesCount + 1];
-
- for (int Index = 0; Index < HandlesCount; Index++)
- {
- int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
-
- KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
-
- if (SyncObj == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- Handles[Index] = SyncObj.WaitEvent;
- }
-
- using (AutoResetEvent WaitEvent = new AutoResetEvent(false))
- {
- if (!SyncWaits.TryAdd(CurrThread, WaitEvent))
- {
- throw new InvalidOperationException();
- }
-
- Handles[HandlesCount] = WaitEvent;
-
- Process.Scheduler.Suspend(CurrThread);
-
- int HandleIndex;
-
- ulong Result = 0;
-
- if (Timeout != ulong.MaxValue)
- {
- HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout));
- }
- else
- {
- HandleIndex = WaitHandle.WaitAny(Handles);
- }
-
- if (HandleIndex == WaitHandle.WaitTimeout)
- {
- Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
- }
- else if (HandleIndex == HandlesCount)
- {
- Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled);
- }
-
- SyncWaits.TryRemove(CurrThread, out _);
-
- Process.Scheduler.Resume(CurrThread);
-
- ThreadState.X0 = Result;
-
- if (Result == 0)
- {
- ThreadState.X1 = (ulong)HandleIndex;
- }
- }
- }
-
- private void SvcCancelSynchronization(AThreadState ThreadState)
- {
- int ThreadHandle = (int)ThreadState.X0;
-
- KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle);
-
- if (Thread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- if (SyncWaits.TryRemove(Thread, out AutoResetEvent WaitEvent))
- {
- WaitEvent.Set();
- }
-
- ThreadState.X0 = 0;
- }
-
- private void SvcGetSystemTick(AThreadState ThreadState)
- {
- ThreadState.X0 = ThreadState.CntpctEl0;
- }
-
- private void SvcConnectToNamedPort(AThreadState ThreadState)
- {
- long StackPtr = (long)ThreadState.X0;
- long NamePtr = (long)ThreadState.X1;
-
- string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8);
-
- //TODO: Validate that app has perms to access the service, and that the service
- //actually exists, return error codes otherwise.
- KSession Session = new KSession(ServiceFactory.MakeService(Name), Name);
-
- ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
-
- ThreadState.X0 = 0;
- ThreadState.X1 = Handle;
- }
-
- private void SvcSendSyncRequest(AThreadState ThreadState)
- {
- SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
- }
-
- private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState)
- {
- SendSyncRequest(
- ThreadState,
- (long)ThreadState.X0,
- (long)ThreadState.X1,
- (int)ThreadState.X2);
- }
-
- private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle)
- {
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- byte[] CmdData = Memory.ReadBytes(CmdPtr, Size);
-
- KSession Session = Process.HandleTable.GetData<KSession>(Handle);
-
- if (Session != null)
- {
- Process.Scheduler.Suspend(CurrThread);
-
- IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
-
- long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
-
- Thread.Yield();
-
- Process.Scheduler.Resume(CurrThread);
-
- ThreadState.X0 = (ulong)Result;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcBreak(AThreadState ThreadState)
- {
- long Reason = (long)ThreadState.X0;
- long Unknown = (long)ThreadState.X1;
- long Info = (long)ThreadState.X2;
-
- Process.PrintStackTrace(ThreadState);
-
- throw new GuestBrokeExecutionException();
- }
-
- private void SvcOutputDebugString(AThreadState ThreadState)
- {
- long Position = (long)ThreadState.X0;
- long Size = (long)ThreadState.X1;
-
- string Str = AMemoryHelper.ReadAsciiString(Memory, Position, Size);
-
- Ns.Log.PrintWarning(LogClass.KernelSvc, Str);
-
- ThreadState.X0 = 0;
- }
-
- private void SvcGetInfo(AThreadState ThreadState)
- {
- long StackPtr = (long)ThreadState.X0;
- int InfoType = (int)ThreadState.X1;
- long Handle = (long)ThreadState.X2;
- int InfoId = (int)ThreadState.X3;
-
- //Fail for info not available on older Kernel versions.
- if (InfoType == 18 ||
- InfoType == 19 ||
- InfoType == 20)
- {
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidInfo);
-
- return;
- }
-
- switch (InfoType)
- {
- case 0:
- ThreadState.X1 = AllowedCpuIdBitmask;
- break;
-
- case 2:
- ThreadState.X1 = MemoryRegions.MapRegionAddress;
- break;
-
- case 3:
- ThreadState.X1 = MemoryRegions.MapRegionSize;
- break;
-
- case 4:
- ThreadState.X1 = MemoryRegions.HeapRegionAddress;
- break;
-
- case 5:
- ThreadState.X1 = MemoryRegions.HeapRegionSize;
- break;
-
- case 6:
- ThreadState.X1 = MemoryRegions.TotalMemoryAvailable;
- break;
-
- case 7:
- ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize;
- break;
-
- case 8:
- ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
- break;
-
- case 11:
- ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
- break;
-
- case 12:
- ThreadState.X1 = MemoryRegions.AddrSpaceStart;
- break;
-
- case 13:
- ThreadState.X1 = MemoryRegions.AddrSpaceSize;
- break;
-
- case 14:
- ThreadState.X1 = MemoryRegions.MapRegionAddress;
- break;
-
- case 15:
- ThreadState.X1 = MemoryRegions.MapRegionSize;
- break;
-
- case 16:
- ThreadState.X1 = IsVirtualMemoryEnabled ? 1 : 0;
- break;
-
- default:
- Process.PrintStackTrace(ThreadState);
-
- throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle:x8} {InfoId}");
- }
-
- ThreadState.X0 = 0;
- }
- }
-}
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
deleted file mode 100644
index c0d1bbd8..00000000
--- a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
+++ /dev/null
@@ -1,291 +0,0 @@
-using ChocolArm64.State;
-using Ryujinx.Core.Logging;
-using Ryujinx.Core.OsHle.Handles;
-using System.Threading;
-
-using static Ryujinx.Core.OsHle.ErrorCode;
-
-namespace Ryujinx.Core.OsHle.Kernel
-{
- partial class SvcHandler
- {
- private void SvcCreateThread(AThreadState ThreadState)
- {
- long EntryPoint = (long)ThreadState.X1;
- long ArgsPtr = (long)ThreadState.X2;
- long StackTop = (long)ThreadState.X3;
- int Priority = (int)ThreadState.X4;
- int ProcessorId = (int)ThreadState.X5;
-
- if ((uint)Priority > 0x3f)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPriority);
-
- return;
- }
-
- if (ProcessorId == -2)
- {
- //TODO: Get this value from the NPDM file.
- ProcessorId = 0;
- }
- else if ((uint)ProcessorId > 3)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
-
- return;
- }
-
- int Handle = Process.MakeThread(
- EntryPoint,
- StackTop,
- ArgsPtr,
- Priority,
- ProcessorId);
-
- ThreadState.X0 = 0;
- ThreadState.X1 = (ulong)Handle;
- }
-
- private void SvcStartThread(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
-
- KThread NewThread = Process.HandleTable.GetData<KThread>(Handle);
-
- if (NewThread != null)
- {
- Process.Scheduler.StartThread(NewThread);
- Process.Scheduler.SetReschedule(NewThread.ProcessorId);
-
- ThreadState.X0 = 0;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcExitThread(AThreadState ThreadState)
- {
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- CurrThread.Thread.StopExecution();
- }
-
- private void SvcSleepThread(AThreadState ThreadState)
- {
- ulong TimeoutNs = ThreadState.X0;
-
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- if (TimeoutNs == 0)
- {
- Process.Scheduler.Yield(CurrThread);
- }
- else
- {
- Process.Scheduler.Suspend(CurrThread);
-
- Thread.Sleep(NsTimeConverter.GetTimeMs(TimeoutNs));
-
- Process.Scheduler.Resume(CurrThread);
- }
- }
-
- private void SvcGetThreadPriority(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X1;
-
- KThread Thread = GetThread(ThreadState.Tpidr, Handle);
-
- if (Thread != null)
- {
- ThreadState.X0 = 0;
- ThreadState.X1 = (ulong)Thread.ActualPriority;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcSetThreadPriority(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
- int Priority = (int)ThreadState.X1;
-
- KThread Thread = GetThread(ThreadState.Tpidr, Handle);
-
- if (Thread != null)
- {
- Thread.SetPriority(Priority);
-
- ThreadState.X0 = 0;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcGetThreadCoreMask(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X2;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "Handle = " + Handle.ToString("x8"));
-
- KThread Thread = GetThread(ThreadState.Tpidr, Handle);
-
- if (Thread != null)
- {
- ThreadState.X0 = 0;
- ThreadState.X1 = (ulong)Thread.IdealCore;
- ThreadState.X2 = (ulong)Thread.CoreMask;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcSetThreadCoreMask(AThreadState ThreadState)
- {
- //FIXME: This is wrong, but the "correct" way to handle
- //this svc causes deadlocks when more often.
- //There is probably something wrong with it still.
- ThreadState.X0 = 0;
-
- return;
-
- int Handle = (int)ThreadState.X0;
- int IdealCore = (int)ThreadState.X1;
- long CoreMask = (long)ThreadState.X2;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc,
- "Handle = " + Handle .ToString("x8") + ", " +
- "IdealCore = " + IdealCore.ToString("x8") + ", " +
- "CoreMask = " + CoreMask .ToString("x16"));
-
- KThread Thread = GetThread(ThreadState.Tpidr, Handle);
-
- if (IdealCore == -2)
- {
- //TODO: Get this value from the NPDM file.
- IdealCore = 0;
-
- CoreMask = 1 << IdealCore;
- }
- else if (IdealCore != -3)
- {
- if ((uint)IdealCore > 3)
- {
- if ((IdealCore | 2) != -1)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{IdealCore:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
-
- return;
- }
- }
- else if ((CoreMask & (1 << IdealCore)) == 0)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreMask);
-
- return;
- }
- }
-
- if (Thread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- //-1 is used as "don't care", so the IdealCore value is ignored.
- //-2 is used as "use NPDM default core id" (handled above).
- //-3 is used as "don't update", the old IdealCore value is kept.
- if (IdealCore != -3)
- {
- Thread.IdealCore = IdealCore;
- }
- else if ((CoreMask & (1 << Thread.IdealCore)) == 0)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{CoreMask:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreMask);
-
- return;
- }
-
- Thread.CoreMask = (int)CoreMask;
-
- Process.Scheduler.TryToRun(Thread);
-
- ThreadState.X0 = 0;
- }
-
- private void SvcGetCurrentProcessorNumber(AThreadState ThreadState)
- {
- ThreadState.X0 = (ulong)Process.GetThread(ThreadState.Tpidr).ActualCore;
- }
-
- private void SvcGetThreadId(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X1;
-
- KThread Thread = GetThread(ThreadState.Tpidr, Handle);
-
- if (Thread != null)
- {
- ThreadState.X0 = 0;
- ThreadState.X1 = (ulong)Thread.ThreadId;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
-
- private void SvcSetThreadActivity(AThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
- bool Active = (int)ThreadState.X1 == 0;
-
- KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
-
- if (Thread != null)
- {
- Process.Scheduler.SetThreadActivity(Thread, Active);
-
- ThreadState.X0 = 0;
- }
- else
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
deleted file mode 100644
index 12bc657a..00000000
--- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs
+++ /dev/null
@@ -1,435 +0,0 @@
-using ChocolArm64.State;
-using Ryujinx.Core.Logging;
-using Ryujinx.Core.OsHle.Handles;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-
-using static Ryujinx.Core.OsHle.ErrorCode;
-
-namespace Ryujinx.Core.OsHle.Kernel
-{
- partial class SvcHandler
- {
- private const int MutexHasListenersMask = 0x40000000;
-
- private void SvcArbitrateLock(AThreadState ThreadState)
- {
- int OwnerThreadHandle = (int)ThreadState.X0;
- long MutexAddress = (long)ThreadState.X1;
- int WaitThreadHandle = (int)ThreadState.X2;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc,
- "OwnerThreadHandle = " + OwnerThreadHandle.ToString("x8") + ", " +
- "MutexAddress = " + MutexAddress .ToString("x16") + ", " +
- "WaitThreadHandle = " + WaitThreadHandle .ToString("x8"));
-
- if (IsPointingInsideKernel(MutexAddress))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
-
- return;
- }
-
- if (IsWordAddressUnaligned(MutexAddress))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment);
-
- return;
- }
-
- KThread OwnerThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
-
- if (OwnerThread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid owner thread handle 0x{OwnerThreadHandle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- KThread WaitThread = Process.HandleTable.GetData<KThread>(WaitThreadHandle);
-
- if (WaitThread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{WaitThreadHandle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- MutexLock(CurrThread, WaitThread, OwnerThreadHandle, WaitThreadHandle, MutexAddress);
-
- ThreadState.X0 = 0;
- }
-
- private void SvcArbitrateUnlock(AThreadState ThreadState)
- {
- long MutexAddress = (long)ThreadState.X0;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexAddress = " + MutexAddress.ToString("x16"));
-
- if (IsPointingInsideKernel(MutexAddress))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
-
- return;
- }
-
- if (IsWordAddressUnaligned(MutexAddress))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment);
-
- return;
- }
-
- MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress);
-
- ThreadState.X0 = 0;
- }
-
- private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState)
- {
- long MutexAddress = (long)ThreadState.X0;
- long CondVarAddress = (long)ThreadState.X1;
- int ThreadHandle = (int)ThreadState.X2;
- ulong Timeout = ThreadState.X3;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc,
- "MutexAddress = " + MutexAddress .ToString("x16") + ", " +
- "CondVarAddress = " + CondVarAddress.ToString("x16") + ", " +
- "ThreadHandle = " + ThreadHandle .ToString("x8") + ", " +
- "Timeout = " + Timeout .ToString("x16"));
-
- if (IsPointingInsideKernel(MutexAddress))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
-
- return;
- }
-
- if (IsWordAddressUnaligned(MutexAddress))
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAlignment);
-
- return;
- }
-
- KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
-
- if (Thread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
-
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
-
- return;
- }
-
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- MutexUnlock(CurrThread, MutexAddress);
-
- if (!CondVarWait(CurrThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout))
- {
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
-
- return;
- }
-
- ThreadState.X0 = 0;
- }
-
- private void SvcSignalProcessWideKey(AThreadState ThreadState)
- {
- long CondVarAddress = (long)ThreadState.X0;
- int Count = (int)ThreadState.X1;
-
- Ns.Log.PrintDebug(LogClass.KernelSvc,
- "CondVarAddress = " + CondVarAddress.ToString("x16") + ", " +
- "Count = " + Count .ToString("x8"));
-
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-
- CondVarSignal(CurrThread, CondVarAddress, Count);
-
- ThreadState.X0 = 0;
- }
-
- private void MutexLock(
- KThread CurrThread,
- KThread WaitThread,
- int OwnerThreadHandle,
- int WaitThreadHandle,
- long MutexAddress)
- {
- lock (Process.ThreadSyncLock)
- {
- int MutexValue = Process.Memory.ReadInt32(MutexAddress);
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
-
- if (MutexValue != (OwnerThreadHandle | MutexHasListenersMask))
- {
- return;
- }
-
- CurrThread.WaitHandle = WaitThreadHandle;
- CurrThread.MutexAddress = MutexAddress;
-
- InsertWaitingMutexThread(OwnerThreadHandle, WaitThread);
- }
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");
-
- Process.Scheduler.EnterWait(CurrThread);
- }
-
- private void MutexUnlock(KThread CurrThread, long MutexAddress)
- {
- lock (Process.ThreadSyncLock)
- {
- //This is the new thread that will now own the mutex.
- //If no threads are waiting for the lock, then it should be null.
- KThread OwnerThread = PopThread(CurrThread.MutexWaiters, x => x.MutexAddress == MutexAddress);
-
- if (OwnerThread != null)
- {
- //Remove all waiting mutex from the old owner,
- //and insert then on the new owner.
- UpdateMutexOwner(CurrThread, OwnerThread, MutexAddress);
-
- CurrThread.UpdatePriority();
-
- int HasListeners = OwnerThread.MutexWaiters.Count > 0 ? MutexHasListenersMask : 0;
-
- Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.WaitHandle);
-
- OwnerThread.WaitHandle = 0;
- OwnerThread.MutexAddress = 0;
- OwnerThread.CondVarAddress = 0;
-
- OwnerThread.MutexOwner = null;
-
- OwnerThread.UpdatePriority();
-
- Process.Scheduler.WakeUp(OwnerThread);
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "Gave mutex to thread id " + OwnerThread.ThreadId + "!");
- }
- else
- {
- Process.Memory.WriteInt32(MutexAddress, 0);
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "No threads waiting mutex!");
- }
- }
- }
-
- private bool CondVarWait(
- KThread WaitThread,
- int WaitThreadHandle,
- long MutexAddress,
- long CondVarAddress,
- ulong Timeout)
- {
- WaitThread.WaitHandle = WaitThreadHandle;
- WaitThread.MutexAddress = MutexAddress;
- WaitThread.CondVarAddress = CondVarAddress;
-
- lock (Process.ThreadSyncLock)
- {
- WaitThread.CondVarSignaled = false;
-
- Process.ThreadArbiterList.Add(WaitThread);
- }
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state...");
-
- if (Timeout != ulong.MaxValue)
- {
- Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout));
-
- lock (Process.ThreadSyncLock)
- {
- WaitThread.MutexOwner?.MutexWaiters.Remove(WaitThread);
-
- if (!WaitThread.CondVarSignaled || WaitThread.MutexOwner != null)
- {
- WaitThread.MutexOwner = null;
-
- Process.ThreadArbiterList.Remove(WaitThread);
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "Timed out...");
-
- return false;
- }
- }
- }
- else
- {
- Process.Scheduler.EnterWait(WaitThread);
- }
-
- return true;
- }
-
- private void CondVarSignal(KThread CurrThread, long CondVarAddress, int Count)
- {
- lock (Process.ThreadSyncLock)
- {
- while (Count == -1 || Count-- > 0)
- {
- KThread WaitThread = PopThread(Process.ThreadArbiterList, x => x.CondVarAddress == CondVarAddress);
-
- if (WaitThread == null)
- {
- Ns.Log.PrintDebug(LogClass.KernelSvc, "No more threads to wake up!");
-
- break;
- }
-
- WaitThread.CondVarSignaled = true;
-
- AcquireMutexValue(WaitThread.MutexAddress);
-
- int MutexValue = Process.Memory.ReadInt32(WaitThread.MutexAddress);
-
- Ns.Log.PrintDebug(LogClass.KernelSvc, "MutexValue = " + MutexValue.ToString("x8"));
-
- if (MutexValue == 0)
- {
- //Give the lock to this thread.
- Process.Memory.WriteInt32(WaitThread.MutexAddress, WaitThread.WaitHandle);
-
- WaitThread.WaitHandle = 0;
- WaitThread.MutexAddress = 0;
- WaitThread.CondVarAddress = 0;
-
- WaitThread.MutexOwner?.UpdatePriority();
-
- WaitThread.MutexOwner = null;
-
- Process.Scheduler.WakeUp(WaitThread);
- }
- else
- {
- //Wait until the lock is released.
- MutexValue &= ~MutexHasListenersMask;
-
- InsertWaitingMutexThread(MutexValue, WaitThread);
-
- MutexValue |= MutexHasListenersMask;
-
- Process.Memory.WriteInt32(WaitThread.MutexAddress, MutexValue);
- }
-
- ReleaseMutexValue(WaitThread.MutexAddress);
- }
- }
- }
-
- private void UpdateMutexOwner(KThread CurrThread, KThread NewOwner, long MutexAddress)
- {
- //Go through all threads waiting for the mutex,
- //and update the MutexOwner field to point to the new owner.
- lock (Process.ThreadSyncLock)
- {
- for (int Index = 0; Index < CurrThread.MutexWaiters.Count; Index++)
- {
- KThread Thread = CurrThread.MutexWaiters[Index];
-
- if (Thread.MutexAddress == MutexAddress)
- {
- CurrThread.MutexWaiters.RemoveAt(Index--);
-
- Thread.MutexOwner = NewOwner;
-
- InsertWaitingMutexThread(NewOwner, Thread);
- }
- }
- }
- }
-
- private void InsertWaitingMutexThread(int OwnerThreadHandle, KThread WaitThread)
- {
- KThread OwnerThread = Process.HandleTable.GetData<KThread>(OwnerThreadHandle);
-
- if (OwnerThread == null)
- {
- Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!");
-
- return;
- }
-
- InsertWaitingMutexThread(OwnerThread, WaitThread);
- }
-
- private void InsertWaitingMutexThread(KThread OwnerThread, KThread WaitThread)
- {
- lock (Process.ThreadSyncLock)
- {
- WaitThread.MutexOwner = OwnerThread;
-
- if (!OwnerThread.MutexWaiters.Contains(WaitThread))
- {
- OwnerThread.MutexWaiters.Add(WaitThread);
-
- OwnerThread.UpdatePriority();
- }
- }
- }
-
- private KThread PopThread(List<KThread> Threads, Func<KThread, bool> Predicate)
- {
- KThread Thread = Threads.OrderBy(x => x.ActualPriority).FirstOrDefault(Predicate);
-
- if (Thread != null)
- {
- Threads.Remove(Thread);
- }
-
- return Thread;
- }
-
- private void AcquireMutexValue(long MutexAddress)
- {
- while (!Process.Memory.AcquireAddress(MutexAddress))
- {
- Thread.Yield();
- }
- }
-
- private void ReleaseMutexValue(long MutexAddress)
- {
- Process.Memory.ReleaseAddress(MutexAddress);
- }
-
- private bool IsPointingInsideKernel(long Address)
- {
- return ((ulong)Address + 0x1000000000) < 0xffffff000;
- }
-
- private bool IsWordAddressUnaligned(long Address)
- {
- return (Address & 3) != 0;
- }
- }
-} \ No newline at end of file