diff --git a/Ryujinx.Audio/IAalOutput.cs b/Ryujinx.Audio/IAalOutput.cs index 5ffeebdd84..f9978ee4d9 100644 --- a/Ryujinx.Audio/IAalOutput.cs +++ b/Ryujinx.Audio/IAalOutput.cs @@ -2,7 +2,11 @@ namespace Ryujinx.Audio { public interface IAalOutput { - int OpenTrack(int SampleRate, int Channels, out AudioFormat Format); + int OpenTrack( + int SampleRate, + int Channels, + ReleaseCallback Callback, + out AudioFormat Format); void CloseTrack(int Track); diff --git a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs index 48dcd19919..f574b46f38 100644 --- a/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/OpenAL/OpenALAudioOut.cs @@ -3,6 +3,7 @@ using OpenTK.Audio.OpenAL; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Threading; namespace Ryujinx.Audio.OpenAL { @@ -22,20 +23,27 @@ namespace Ryujinx.Audio.OpenAL public ALFormat Format { get; private set; } + private ReleaseCallback Callback; + public PlaybackState State { get; set; } + private bool ShouldCallReleaseCallback; + private ConcurrentDictionary Buffers; private Queue QueuedTagsQueue; private Queue ReleasedTagsQueue; + private int LastReleasedCount; + private bool Disposed; - public Track(int SampleRate, ALFormat Format) + public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback) { this.SampleRate = SampleRate; this.Format = Format; + this.Callback = Callback; State = PlaybackState.Stopped; @@ -109,11 +117,42 @@ namespace Ryujinx.Audio.OpenAL AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount); + CheckReleaseChanges(ReleasedCount); + if (ReleasedCount > 0) { AL.SourceUnqueueBuffers(SourceId, ReleasedCount); } } + + public void CallReleaseCallbackIfNeeded() + { + CheckReleaseChanges(); + + if (ShouldCallReleaseCallback) + { + ShouldCallReleaseCallback = false; + + Callback(); + } + } + + private void CheckReleaseChanges() + { + AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount); + + CheckReleaseChanges(ReleasedCount); + } + + private void CheckReleaseChanges(int NewReleasedCount) + { + if (LastReleasedCount != NewReleasedCount) + { + LastReleasedCount = NewReleasedCount; + + ShouldCallReleaseCallback = true; + } + } private void SyncQueuedTags() { @@ -156,18 +195,46 @@ namespace Ryujinx.Audio.OpenAL private ConcurrentDictionary Tracks; + private Thread AudioPollerThread; + + private bool KeepPolling; + public OpenALAudioOut() { Context = new AudioContext(); Tracks = new ConcurrentDictionary(); + + KeepPolling = true; + + AudioPollerThread = new Thread(AudioPollerWork); + + AudioPollerThread.Start(); } - public int OpenTrack(int SampleRate, int Channels, out AudioFormat Format) + private void AudioPollerWork() + { + do + { + foreach (Track Td in Tracks.Values) + { + Td.CallReleaseCallbackIfNeeded(); + } + + Thread.Yield(); + } + while (KeepPolling); + } + + public int OpenTrack( + int SampleRate, + int Channels, + ReleaseCallback Callback, + out AudioFormat Format) { Format = AudioFormat.PcmInt16; - Track Td = new Track(SampleRate, GetALFormat(Channels, Format)); + Track Td = new Track(SampleRate, GetALFormat(Channels, Format), Callback); for (int Id = 0; Id < MaxTracks; Id++) { @@ -292,5 +359,7 @@ namespace Ryujinx.Audio.OpenAL return PlaybackState.Stopped; } + + } } \ No newline at end of file diff --git a/Ryujinx.Audio/ReleaseCallback.cs b/Ryujinx.Audio/ReleaseCallback.cs new file mode 100644 index 0000000000..f534e02cdd --- /dev/null +++ b/Ryujinx.Audio/ReleaseCallback.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Audio +{ + public delegate void ReleaseCallback(); +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/AppletStateMgr.cs b/Ryujinx.Core/OsHle/AppletStateMgr.cs new file mode 100644 index 0000000000..cd168b77a8 --- /dev/null +++ b/Ryujinx.Core/OsHle/AppletStateMgr.cs @@ -0,0 +1,62 @@ +using Ryujinx.Core.OsHle.IpcServices.Am; +using Ryujinx.Core.OsHle.Handles; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.Core.OsHle +{ + class AppletStateMgr : IDisposable + { + private ConcurrentQueue Messages; + + public FocusState FocusState { get; private set; } + + public KEvent MessageEvent { get; private set; } + + public AppletStateMgr() + { + Messages = new ConcurrentQueue(); + + MessageEvent = new KEvent(); + } + + public void SetFocus(bool IsFocused) + { + FocusState = IsFocused + ? FocusState.InFocus + : FocusState.OutOfFocus; + + EnqueueMessage(MessageInfo.FocusStateChanged); + } + + public void EnqueueMessage(MessageInfo Message) + { + Messages.Enqueue(Message); + + MessageEvent.Handle.Set(); + } + + public bool TryDequeueMessage(out MessageInfo Message) + { + if (Messages.Count < 2) + { + MessageEvent.Handle.Reset(); + } + + return Messages.TryDequeue(out Message); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + MessageEvent.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/CondVar.cs b/Ryujinx.Core/OsHle/CondVar.cs index f5fe3d292e..f1b846d08c 100644 --- a/Ryujinx.Core/OsHle/CondVar.cs +++ b/Ryujinx.Core/OsHle/CondVar.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle private bool OwnsCondVarValue; - private List WaitingThreads; + private List WaitingThreads; public CondVar(Process Process, long CondVarAddress, long Timeout) { @@ -21,10 +21,10 @@ namespace Ryujinx.Core.OsHle this.CondVarAddress = CondVarAddress; this.Timeout = Timeout; - WaitingThreads = new List(); + WaitingThreads = new List(); } - public bool WaitForSignal(HThread Thread) + public bool WaitForSignal(KThread Thread) { int Count = Process.Memory.ReadInt32(CondVarAddress); @@ -66,7 +66,7 @@ namespace Ryujinx.Core.OsHle return true; } - public void SetSignal(HThread Thread, int Count) + public void SetSignal(KThread Thread, int Count) { lock (WaitingThreads) { diff --git a/Ryujinx.Core/OsHle/FileDesc.cs b/Ryujinx.Core/OsHle/FileDesc.cs deleted file mode 100644 index 4be83bb07f..0000000000 --- a/Ryujinx.Core/OsHle/FileDesc.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Core.OsHle -{ - class FileDesc - { - public string Name { get; private set; } - - public FileDesc(string Name) - { - this.Name = Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/GlobalStateTable.cs b/Ryujinx.Core/OsHle/GlobalStateTable.cs new file mode 100644 index 0000000000..ffc9f26270 --- /dev/null +++ b/Ryujinx.Core/OsHle/GlobalStateTable.cs @@ -0,0 +1,62 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle +{ + class GlobalStateTable + { + private ConcurrentDictionary DictByProcess; + + public GlobalStateTable() + { + DictByProcess = new ConcurrentDictionary(); + } + + public int Add(Process Process, object Obj) + { + IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary()); + + return Dict.Add(Obj); + } + + public object GetData(Process Process, int Id) + { + if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) + { + return Dict.GetData(Id); + } + + return null; + } + + public T GetData(Process Process, int Id) + { + if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) + { + return Dict.GetData(Id); + } + + return default(T); + } + + public object Delete(Process Process, int Id) + { + if (DictByProcess.TryGetValue(Process, out IdDictionary Dict)) + { + return Dict.Delete(Id); + } + + return null; + } + + public ICollection DeleteProcess(Process Process) + { + if (DictByProcess.TryRemove(Process, out IdDictionary Dict)) + { + return Dict.Clear(); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HDomain.cs b/Ryujinx.Core/OsHle/Handles/HDomain.cs deleted file mode 100644 index 26c604554f..0000000000 --- a/Ryujinx.Core/OsHle/Handles/HDomain.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; - -namespace Ryujinx.Core.OsHle.Handles -{ - class HDomain : HSession, IDisposable - { - private IdDictionary Objects; - - public HDomain(HSession Session) : base(Session) - { - Objects = new IdDictionary(); - } - - public int Add(object Obj) - { - return Objects.Add(Obj); - } - - public bool Delete(int Id) - { - return Objects.Delete(Id); - } - - public object GetObject(int Id) - { - return Objects.GetData(Id); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - foreach (object Obj in Objects) - { - if (Obj != this && Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HEvent.cs b/Ryujinx.Core/OsHle/Handles/HEvent.cs deleted file mode 100644 index 4e881ca249..0000000000 --- a/Ryujinx.Core/OsHle/Handles/HEvent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.Core.OsHle.Handles -{ - class HEvent - { - - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HSession.cs b/Ryujinx.Core/OsHle/Handles/HSession.cs deleted file mode 100644 index f30e91f98d..0000000000 --- a/Ryujinx.Core/OsHle/Handles/HSession.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.Core.OsHle.IpcServices; - -namespace Ryujinx.Core.OsHle.Handles -{ - class HSession - { - public IIpcService Service { get; private set; } - - public bool IsInitialized { get; private set; } - - public int State { get; set; } - - public HSession(IIpcService Service) - { - this.Service = Service; - } - - public HSession(HSession Session) - { - Service = Session.Service; - IsInitialized = Session.IsInitialized; - } - - public void Initialize() - { - IsInitialized = true; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HSessionObj.cs b/Ryujinx.Core/OsHle/Handles/HSessionObj.cs deleted file mode 100644 index ed0530f74c..0000000000 --- a/Ryujinx.Core/OsHle/Handles/HSessionObj.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Ryujinx.Core.OsHle.Handles -{ - class HSessionObj : HSession, IDisposable - { - public object Obj { get; private set; } - - public HSessionObj(HSession Session, object Obj) : base(Session) - { - this.Obj = Obj; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing && Obj != null) - { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/KEvent.cs b/Ryujinx.Core/OsHle/Handles/KEvent.cs new file mode 100644 index 0000000000..96ff01f7ff --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/KEvent.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Core.OsHle.Handles +{ + class KEvent : KSynchronizationObject { } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs index 1156e035fd..2c8098834e 100644 --- a/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs +++ b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs @@ -1,8 +1,8 @@ -using System; +using System.Collections.Generic; namespace Ryujinx.Core.OsHle.Handles { - class KProcessHandleTable : IDisposable + class KProcessHandleTable { private IdDictionary Handles; @@ -21,43 +21,14 @@ namespace Ryujinx.Core.OsHle.Handles return Handles.GetData(Handle); } - public bool ReplaceData(int Id, object Data) + public object CloseHandle(int Handle) { - return Handles.ReplaceData(Id, Data); - } - - public bool CloseHandle(int Handle) - { - object Data = Handles.GetData(Handle); - - if (Data is HTransferMem TMem) - { - TMem.Memory.Manager.Reprotect( - TMem.Position, - TMem.Size, - TMem.Perm); - } - return Handles.Delete(Handle); } - public void Dispose() + public ICollection Clear() { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - foreach (object Obj in Handles) - { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - } - } + return Handles.Clear(); } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs index b111607811..9575429838 100644 --- a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs +++ b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs @@ -5,15 +5,15 @@ using System.Threading; namespace Ryujinx.Core.OsHle.Handles { - public class KProcessScheduler : IDisposable + class KProcessScheduler : IDisposable { private class SchedulerThread : IDisposable { - public HThread Thread { get; private set; } + public KThread Thread { get; private set; } public AutoResetEvent WaitEvent { get; private set; } - public SchedulerThread(HThread Thread) + public SchedulerThread(KThread Thread) { this.Thread = Thread; @@ -95,7 +95,7 @@ namespace Ryujinx.Core.OsHle.Handles } } - private ConcurrentDictionary AllThreads; + private ConcurrentDictionary AllThreads; private ThreadQueue[] WaitingToRun; @@ -105,7 +105,7 @@ namespace Ryujinx.Core.OsHle.Handles public KProcessScheduler() { - AllThreads = new ConcurrentDictionary(); + AllThreads = new ConcurrentDictionary(); WaitingToRun = new ThreadQueue[4]; @@ -119,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Handles SchedLock = new object(); } - public void StartThread(HThread Thread) + public void StartThread(KThread Thread) { lock (SchedLock) { @@ -164,7 +164,7 @@ namespace Ryujinx.Core.OsHle.Handles } } - public void Resume(HThread CurrThread) + public void Resume(KThread CurrThread) { SchedulerThread SchedThread; @@ -183,7 +183,7 @@ namespace Ryujinx.Core.OsHle.Handles TryResumingExecution(SchedThread); } - public bool WaitForSignal(HThread Thread, int Timeout = -1) + public bool WaitForSignal(KThread Thread, int Timeout = -1) { SchedulerThread SchedThread; @@ -230,7 +230,7 @@ namespace Ryujinx.Core.OsHle.Handles private void TryResumingExecution(SchedulerThread SchedThread) { - HThread Thread = SchedThread.Thread; + KThread Thread = SchedThread.Thread; lock (SchedLock) { @@ -249,7 +249,7 @@ namespace Ryujinx.Core.OsHle.Handles Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); } - public void Yield(HThread Thread) + public void Yield(KThread Thread) { SchedulerThread SchedThread; @@ -295,11 +295,11 @@ namespace Ryujinx.Core.OsHle.Handles } } - public void Signal(params HThread[] Threads) + public void Signal(params KThread[] Threads) { lock (SchedLock) { - foreach (HThread Thread in Threads) + foreach (KThread Thread in Threads) { if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) { @@ -314,7 +314,7 @@ namespace Ryujinx.Core.OsHle.Handles } } - private string GetDbgThreadInfo(HThread Thread) + private string GetDbgThreadInfo(KThread Thread) { return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}"; } diff --git a/Ryujinx.Core/OsHle/Handles/KSession.cs b/Ryujinx.Core/OsHle/Handles/KSession.cs new file mode 100644 index 0000000000..6934e52259 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/KSession.cs @@ -0,0 +1,28 @@ +using Ryujinx.Core.OsHle.IpcServices; +using System; + +namespace Ryujinx.Core.OsHle.Handles +{ + class KSession : IDisposable + { + public IpcService Service { get; private set; } + + public KSession(IpcService Service) + { + this.Service = Service; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing && Service is IDisposable DisposableService) + { + DisposableService.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs b/Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs new file mode 100644 index 0000000000..015b814a42 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading; + +namespace Ryujinx.Core.OsHle.Handles +{ + class KSynchronizationObject : IDisposable + { + public ManualResetEvent Handle { get; private set; } + + public KSynchronizationObject() + { + Handle = new ManualResetEvent(false); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Handle.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HThread.cs b/Ryujinx.Core/OsHle/Handles/KThread.cs similarity index 79% rename from Ryujinx.Core/OsHle/Handles/HThread.cs rename to Ryujinx.Core/OsHle/Handles/KThread.cs index c631cedc6c..aa1b27bede 100644 --- a/Ryujinx.Core/OsHle/Handles/HThread.cs +++ b/Ryujinx.Core/OsHle/Handles/KThread.cs @@ -2,7 +2,7 @@ using ChocolArm64; namespace Ryujinx.Core.OsHle.Handles { - public class HThread + class KThread : KSynchronizationObject { public AThread Thread { get; private set; } @@ -11,7 +11,7 @@ namespace Ryujinx.Core.OsHle.Handles public int ThreadId => Thread.ThreadId; - public HThread(AThread Thread, int ProcessorId, int Priority) + public KThread(AThread Thread, int ProcessorId, int Priority) { this.Thread = Thread; this.ProcessorId = ProcessorId; diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs index c3f8cd8b00..240c08dbd9 100644 --- a/Ryujinx.Core/OsHle/Horizon.cs +++ b/Ryujinx.Core/OsHle/Horizon.cs @@ -16,8 +16,10 @@ namespace Ryujinx.Core.OsHle private ConcurrentDictionary Processes; - internal HSharedMem HidSharedMem; - internal HSharedMem FontSharedMem; + internal HSharedMem HidSharedMem { get; private set; } + internal HSharedMem FontSharedMem { get; private set; } + + internal KEvent VsyncEvent { get; private set; } private Switch Ns; @@ -32,6 +34,8 @@ namespace Ryujinx.Core.OsHle HidSharedMem = new HSharedMem(); FontSharedMem = new HSharedMem(); + + VsyncEvent = new KEvent(); } public void LoadCart(string ExeFsDir, string RomFsFile = null) @@ -91,6 +95,8 @@ namespace Ryujinx.Core.OsHle MainProcess.Run(IsNro); } + public void SignalVsync() => VsyncEvent.Handle.Set(); + private Process MakeProcess() { Process Process; @@ -109,9 +115,16 @@ namespace Ryujinx.Core.OsHle Processes.TryAdd(ProcessId, Process); } + InitializeProcess(Process); + return Process; } + private void InitializeProcess(Process Process) + { + Process.AppletState.SetFocus(true); + } + internal void ExitProcess(int ProcessId) { if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi) @@ -171,6 +184,8 @@ namespace Ryujinx.Core.OsHle Process.StopAllThreadsAsync(); Process.Dispose(); } + + VsyncEvent.Dispose(); } } } diff --git a/Ryujinx.Core/OsHle/IdDictionary.cs b/Ryujinx.Core/OsHle/IdDictionary.cs index 0b90924616..0746ae81b1 100644 --- a/Ryujinx.Core/OsHle/IdDictionary.cs +++ b/Ryujinx.Core/OsHle/IdDictionary.cs @@ -1,11 +1,10 @@ using System; -using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; namespace Ryujinx.Core.OsHle { - class IdDictionary : IEnumerable + class IdDictionary { private ConcurrentDictionary Objs; @@ -39,18 +38,6 @@ namespace Ryujinx.Core.OsHle throw new InvalidOperationException(); } - public bool ReplaceData(int Id, object Data) - { - if (Objs.ContainsKey(Id)) - { - Objs[Id] = Data; - - return true; - } - - return false; - } - public object GetData(int Id) { if (Objs.TryGetValue(Id, out object Data)) @@ -71,31 +58,25 @@ namespace Ryujinx.Core.OsHle return default(T); } - public bool Delete(int Id) + public object Delete(int Id) { if (Objs.TryRemove(Id, out object Obj)) { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - FreeIdHint = Id; - return true; + return Obj; } - return false; + return null; } - IEnumerator IEnumerable.GetEnumerator() + public ICollection Clear() { - return Objs.Values.GetEnumerator(); - } + ICollection Values = Objs.Values; - IEnumerator IEnumerable.GetEnumerator() - { - return Objs.Values.GetEnumerator(); + Objs.Clear(); + + return Values; } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs b/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs deleted file mode 100644 index 1ef0c40823..0000000000 --- a/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.Core.OsHle.Ipc -{ - enum IpcDomCmd - { - SendMsg = 1, - DeleteObj = 2 - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs index f2179a962c..35a2535bee 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs @@ -1,6 +1,5 @@ using ChocolArm64.Memory; using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.IpcServices; using System; using System.IO; @@ -8,20 +7,15 @@ namespace Ryujinx.Core.OsHle.Ipc { static class IpcHandler { - private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; - private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; - public static void IpcCall( Switch Ns, Process Process, AMemory Memory, - HSession Session, + KSession Session, IpcMessage Request, - int ThreadId, - long CmdPtr, - int HndId) + long CmdPtr) { - IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request); + IpcMessage Response = new IpcMessage(); using (MemoryStream Raw = new MemoryStream(Request.RawData)) { @@ -29,94 +23,25 @@ namespace Ryujinx.Core.OsHle.Ipc if (Request.Type == IpcMessageType.Request) { - string ServiceName = Session.Service.GetType().Name; + Response.Type = IpcMessageType.Response; - ServiceProcessRequest ProcReq = null; - - bool IgnoreNullPR = false; - - string DbgServiceName = string.Empty; - - if (Session is HDomain Dom) + using (MemoryStream ResMS = new MemoryStream()) { - if (Request.DomCmd == IpcDomCmd.SendMsg) - { - long Magic = ReqReader.ReadInt64(); - int CmdId = (int)ReqReader.ReadInt64(); + BinaryWriter ResWriter = new BinaryWriter(ResMS); - object Obj = Dom.GetObject(Request.DomObjId); + ServiceCtx Context = new ServiceCtx( + Ns, + Process, + Memory, + Session, + Request, + Response, + ReqReader, + ResWriter); - if (Obj is HDomain) - { - Session.Service.Commands.TryGetValue(CmdId, out ProcReq); + Session.Service.CallMethod(Context); - DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - else if (Obj != null) - { - ((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq); - - DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - } - else if (Request.DomCmd == IpcDomCmd.DeleteObj) - { - Dom.Delete(Request.DomObjId); - - Response = FillResponse(Response, 0); - - IgnoreNullPR = true; - } - } - else - { - long Magic = ReqReader.ReadInt64(); - int CmdId = (int)ReqReader.ReadInt64(); - - if (Session is HSessionObj) - { - object Obj = ((HSessionObj)Session).Obj; - - ((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq); - - DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - else - { - Session.Service.Commands.TryGetValue(CmdId, out ProcReq); - - DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - } - - DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}"; - - Logging.Debug($"IpcMessage: {DbgServiceName}"); - - if (ProcReq != null) - { - using (MemoryStream ResMS = new MemoryStream()) - { - BinaryWriter ResWriter = new BinaryWriter(ResMS); - - ServiceCtx Context = new ServiceCtx( - Ns, - Process, - Memory, - Session, - Request, - Response, - ReqReader, - ResWriter); - - long Result = ProcReq(Context); - - Response = FillResponse(Response, Result, ResMS.ToArray()); - } - } - else if (!IgnoreNullPR) - { - throw new NotImplementedException(DbgServiceName); + Response.RawData = ResMS.ToArray(); } } else if (Request.Type == IpcMessageType.Control) @@ -128,11 +53,7 @@ namespace Ryujinx.Core.OsHle.Ipc { case 0: { - HDomain Dom = new HDomain(Session); - - Process.HandleTable.ReplaceData(HndId, Dom); - - Request = FillResponse(Response, 0, Dom.Add(Dom)); + Request = FillResponse(Response, 0, Session.Service.ConvertToDomain()); break; } @@ -198,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Ipc { BinaryWriter Writer = new BinaryWriter(MS); - Writer.Write(SfcoMagic); + Writer.Write(IpcMagic.Sfco); Writer.Write(Result); if (Data != null) diff --git a/Ryujinx.Core/OsHle/Ipc/IpcLog.cs b/Ryujinx.Core/OsHle/Ipc/IpcLog.cs index dfec7ccfd4..01915d91a4 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcLog.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcLog.cs @@ -125,8 +125,7 @@ namespace Ryujinx.Core.OsHle.Ipc Reader.ReadInt64(); //Padding - IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + - $" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine + + IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + Environment.NewLine + $" DomObjId: {DomObjId.ToString()}" + Environment.NewLine; } diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMagic.cs b/Ryujinx.Core/OsHle/Ipc/IpcMagic.cs new file mode 100644 index 0000000000..e3b8c74eb2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcMagic.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Core.OsHle.Ipc +{ + abstract class IpcMagic + { + public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; + public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs index ebb3dbca04..a992424655 100644 --- a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs +++ b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs @@ -17,10 +17,6 @@ namespace Ryujinx.Core.OsHle.Ipc public List ResponseObjIds { get; private set; } - public bool IsDomain { get; private set; } - public IpcDomCmd DomCmd { get; private set; } - public int DomObjId { get; private set; } - public byte[] RawData { get; set; } public IpcMessage() @@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc ResponseObjIds = new List(); } - public IpcMessage(bool Domain) : this() + public IpcMessage(byte[] Data, long CmdPtr) : this() { - IsDomain = Domain; - } - - public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this() - { - Logging.Ipc(Data, CmdPtr, Domain); - using (MemoryStream MS = new MemoryStream(Data)) { BinaryReader Reader = new BinaryReader(MS); - Initialize(Reader, CmdPtr, Domain); + Initialize(Reader, CmdPtr); } } - private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain) + private void Initialize(BinaryReader Reader, long CmdPtr) { - IsDomain = Domain; - int Word0 = Reader.ReadInt32(); int Word1 = Reader.ReadInt32(); @@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc RecvListCount = 0; } - if (Domain && Type == IpcMessageType.Request) - { - int DomWord0 = Reader.ReadInt32(); - - DomCmd = (IpcDomCmd)(DomWord0 & 0xff); - - RawDataSize = (DomWord0 >> 16) & 0xffff; - - DomObjId = Reader.ReadInt32(); - - Reader.ReadInt64(); //Padding - } - RawData = Reader.ReadBytes(RawDataSize); Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); @@ -165,9 +139,7 @@ namespace Ryujinx.Core.OsHle.Ipc //This is the weirdest padding I've seen so far... int Pad1 = 0x10 - Pad0; - DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4; - - DataLength += ResponseObjIds.Count; + DataLength = (DataLength + Pad0 + Pad1) / 4; Word1 = DataLength & 0x3ff; @@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc MS.Seek(Pad0, SeekOrigin.Current); - if (IsDomain) - { - Writer.Write(ResponseObjIds.Count); - Writer.Write(0); - Writer.Write(0L); - } - if (RawData != null) { Writer.Write(RawData); } - foreach (int Id in ResponseObjIds) - { - Writer.Write(Id); - } - Writer.Write(new byte[Pad1]); return MS.ToArray(); diff --git a/Ryujinx.Core/OsHle/KernelErr.cs b/Ryujinx.Core/OsHle/KernelErr.cs index 19983af19d..e476f631fd 100644 --- a/Ryujinx.Core/OsHle/KernelErr.cs +++ b/Ryujinx.Core/OsHle/KernelErr.cs @@ -6,6 +6,5 @@ namespace Ryujinx.Core.OsHle public const int InvalidHandle = 114; public const int Timeout = 117; public const int InvalidInfo = 120; - public const int InvalidIpcReq = 123; } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Mutex.cs b/Ryujinx.Core/OsHle/Mutex.cs index c619e12174..7a0e8b6cf5 100644 --- a/Ryujinx.Core/OsHle/Mutex.cs +++ b/Ryujinx.Core/OsHle/Mutex.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Core.OsHle private object EnterWaitLock; - private ConcurrentQueue WaitingThreads; + private ConcurrentQueue WaitingThreads; public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle) { @@ -27,10 +27,10 @@ namespace Ryujinx.Core.OsHle EnterWaitLock = new object(); - WaitingThreads = new ConcurrentQueue(); + WaitingThreads = new ConcurrentQueue(); } - public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle) + public void WaitForLock(KThread RequestingThread, int RequestingThreadHandle) { AcquireMutexValue(); @@ -83,11 +83,11 @@ namespace Ryujinx.Core.OsHle ReleaseMutexValue(); - HThread[] UnlockedThreads = new HThread[WaitingThreads.Count]; + KThread[] UnlockedThreads = new KThread[WaitingThreads.Count]; int Index = 0; - while (WaitingThreads.TryDequeue(out HThread Thread)) + while (WaitingThreads.TryDequeue(out KThread Thread)) { UnlockedThreads[Index++] = Thread; } diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index 239b198039..1846e576d3 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -5,6 +5,7 @@ using Ryujinx.Core.Loaders; using Ryujinx.Core.Loaders.Executables; using Ryujinx.Core.OsHle.Exceptions; using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.IpcServices.NvServices; using Ryujinx.Core.OsHle.Svc; using System; using System.Collections.Concurrent; @@ -31,21 +32,21 @@ namespace Ryujinx.Core.OsHle public AMemory Memory { get; private set; } - public ServiceMgr Services { get; private set; } - public KProcessScheduler Scheduler { get; private set; } public KProcessHandleTable HandleTable { get; private set; } + public AppletStateMgr AppletState { get; private set; } + private SvcHandler SvcHandler; private ConcurrentDictionary TlsSlots; - private ConcurrentDictionary ThreadsByTpidr; + private ConcurrentDictionary ThreadsByTpidr; private List Executables; - private HThread MainThread; + private KThread MainThread; private long ImageBase; @@ -60,17 +61,17 @@ namespace Ryujinx.Core.OsHle Memory = new AMemory(); - Services = new ServiceMgr(); - HandleTable = new KProcessHandleTable(); - Scheduler = new KProcessScheduler(); + Scheduler = new KProcessScheduler(); + + AppletState = new AppletStateMgr(); SvcHandler = new SvcHandler(Ns, this); TlsSlots = new ConcurrentDictionary(); - ThreadsByTpidr = new ConcurrentDictionary(); + ThreadsByTpidr = new ConcurrentDictionary(); Executables = new List(); @@ -132,7 +133,7 @@ namespace Ryujinx.Core.OsHle return false; } - MainThread = HandleTable.GetData(Handle); + MainThread = HandleTable.GetData(Handle); if (NeedsHbAbi) { @@ -186,7 +187,7 @@ namespace Ryujinx.Core.OsHle AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint); - HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority); + KThread ThreadHnd = new KThread(Thread, ProcessorId, Priority); int Handle = HandleTable.OpenHandle(ThreadHnd); @@ -311,9 +312,9 @@ namespace Ryujinx.Core.OsHle return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize); } - public HThread GetThread(long Tpidr) + public KThread GetThread(long Tpidr) { - if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread)) + if (!ThreadsByTpidr.TryGetValue(Tpidr, out KThread Thread)) { Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!"); } @@ -344,11 +345,27 @@ namespace Ryujinx.Core.OsHle } Disposed = true; - - Services.Dispose(); - HandleTable.Dispose(); + + foreach (object Obj in HandleTable.Clear()) + { + if (Obj is KSession Session) + { + Session.Dispose(); + } + } + + ServiceNvDrv.Fds.DeleteProcess(this); + + ServiceNvDrv.NvMaps.DeleteProcess(this); + + ServiceNvDrv.NvMapsById.DeleteProcess(this); + Scheduler.Dispose(); + + AppletState.Dispose(); + SvcHandler.Dispose(); + Memory.Dispose(); Logging.Info($"Process {ProcessId} exiting..."); diff --git a/Ryujinx.Core/OsHle/ServiceCtx.cs b/Ryujinx.Core/OsHle/ServiceCtx.cs index 60c378d5a7..7716507fe8 100644 --- a/Ryujinx.Core/OsHle/ServiceCtx.cs +++ b/Ryujinx.Core/OsHle/ServiceCtx.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle public Switch Ns { get; private set; } public Process Process { get; private set; } public AMemory Memory { get; private set; } - public HSession Session { get; private set; } + public KSession Session { get; private set; } public IpcMessage Request { get; private set; } public IpcMessage Response { get; private set; } public BinaryReader RequestData { get; private set; } @@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle Switch Ns, Process Process, AMemory Memory, - HSession Session, + KSession Session, IpcMessage Request, IpcMessage Response, BinaryReader RequestData, diff --git a/Ryujinx.Core/OsHle/ServiceMgr.cs b/Ryujinx.Core/OsHle/ServiceMgr.cs deleted file mode 100644 index 39f6236859..0000000000 --- a/Ryujinx.Core/OsHle/ServiceMgr.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Ryujinx.Core.OsHle.IpcServices; -using Ryujinx.Core.OsHle.IpcServices.Acc; -using Ryujinx.Core.OsHle.IpcServices.Am; -using Ryujinx.Core.OsHle.IpcServices.Apm; -using Ryujinx.Core.OsHle.IpcServices.Aud; -using Ryujinx.Core.OsHle.IpcServices.Bsd; -using Ryujinx.Core.OsHle.IpcServices.Friend; -using Ryujinx.Core.OsHle.IpcServices.FspSrv; -using Ryujinx.Core.OsHle.IpcServices.Hid; -using Ryujinx.Core.OsHle.IpcServices.Lm; -using Ryujinx.Core.OsHle.IpcServices.Nifm; -using Ryujinx.Core.OsHle.IpcServices.Ns; -using Ryujinx.Core.OsHle.IpcServices.NvServices; -using Ryujinx.Core.OsHle.IpcServices.Pctl; -using Ryujinx.Core.OsHle.IpcServices.Pl; -using Ryujinx.Core.OsHle.IpcServices.Set; -using Ryujinx.Core.OsHle.IpcServices.Sfdnsres; -using Ryujinx.Core.OsHle.IpcServices.Sm; -using Ryujinx.Core.OsHle.IpcServices.Ssl; -using Ryujinx.Core.OsHle.IpcServices.Time; -using Ryujinx.Core.OsHle.IpcServices.Vi; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Core.OsHle -{ - class ServiceMgr : IDisposable - { - private Dictionary Services; - - public ServiceMgr() - { - Services = new Dictionary(); - } - - public IIpcService GetService(string Name) - { - lock (Services) - { - string LookUpName; - - //Same service with different privileges. - if (Name.EndsWith(":a") || - Name.EndsWith(":m") || - Name.EndsWith(":s") || - Name.EndsWith(":su") || - Name.EndsWith(":u") || - Name.EndsWith(":u0") || - Name.EndsWith(":u1")) - { - LookUpName = Name.Substring(0, Name.IndexOf(':')); - } - else - { - LookUpName = Name; - } - - if (!Services.TryGetValue(LookUpName, out IIpcService Service)) - { - switch (Name) - { - case "acc:u0": Service = new ServiceAcc(); break; - case "aoc:u": Service = new ServiceNs(); break; - case "apm": Service = new ServiceApm(); break; - case "apm:p": Service = new ServiceApm(); break; - case "appletOE": Service = new ServiceAppletOE(); break; - case "audout:u": Service = new ServiceAudOut(); break; - case "audren:u": Service = new ServiceAudRen(); break; - case "bsd:s": Service = new ServiceBsd(); break; - case "bsd:u": Service = new ServiceBsd(); break; - case "friend:a": Service = new ServiceFriend(); break; - case "fsp-srv": Service = new ServiceFspSrv(); break; - case "hid": Service = new ServiceHid(); break; - case "lm": Service = new ServiceLm(); break; - case "nifm:u": Service = new ServiceNifm(); break; - case "nvdrv": Service = new ServiceNvDrv(); break; - case "nvdrv:a": Service = new ServiceNvDrv(); break; - case "pctl:a": Service = new ServicePctl(); break; - case "pl:u": Service = new ServicePl(); break; - case "set": Service = new ServiceSet(); break; - case "set:sys": Service = new ServiceSetSys(); break; - case "sfdnsres": Service = new ServiceSfdnsres(); break; - case "sm:": Service = new ServiceSm(); break; - case "ssl": Service = new ServiceSsl(); break; - case "time:s": Service = new ServiceTime(); break; - case "time:u": Service = new ServiceTime(); break; - case "vi:m": Service = new ServiceVi(); break; - case "vi:s": Service = new ServiceVi(); break; - case "vi:u": Service = new ServiceVi(); break; - } - - if (Service == null) - { - throw new NotImplementedException(Name); - } - - Services.Add(LookUpName, Service); - } - - return Service; - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - lock (Services) - { - foreach (IIpcService Service in Services.Values) - { - if (Service is IDisposable DisposableSrv) - { - DisposableSrv.Dispose(); - } - } - - Services.Clear(); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs b/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs index ab491eac79..9e309142c9 100644 --- a/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs +++ b/Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Acc { - class IManagerForApplication : IIpcService + class IManagerForApplication : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IManagerForApplication() { diff --git a/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs b/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs index 77fe2b48cb..bdeadfe88b 100644 --- a/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs +++ b/Ryujinx.Core/OsHle/Services/Acc/IProfile.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Acc { - class IProfile : IIpcService + class IProfile : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IProfile() { diff --git a/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs b/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs index 8844bb5d1c..8b0a99d9de 100644 --- a/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs +++ b/Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Acc { - class ServiceAcc : IIpcService + class ServiceAcc : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceAcc() { diff --git a/Ryujinx.Core/OsHle/Services/Am/AmErr.cs b/Ryujinx.Core/OsHle/Services/Am/AmErr.cs new file mode 100644 index 0000000000..be1658742b --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/AmErr.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + static class AmErr + { + public const int NoMessages = 3; + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/FocusState.cs b/Ryujinx.Core/OsHle/Services/Am/FocusState.cs new file mode 100644 index 0000000000..08dffe3b69 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/FocusState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + enum FocusState + { + InFocus = 1, + OutOfFocus = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs b/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs index c989cdd449..685a748235 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs @@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; using System.IO; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IApplicationFunctions : IIpcService + class IApplicationFunctions : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IApplicationFunctions() { diff --git a/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs b/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs index 5417d7f045..81bb2711a9 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IApplicationProxy : IIpcService + class IApplicationProxy : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IApplicationProxy() { diff --git a/Ryujinx.Core/OsHle/Services/Am/IAudioController.cs b/Ryujinx.Core/OsHle/Services/Am/IAudioController.cs index 1212f1e241..aa927d601a 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IAudioController.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IAudioController.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IAudioController : IIpcService + class IAudioController : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IAudioController() { diff --git a/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs b/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs index 2999bbbae7..ec1fc7746b 100644 --- a/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs +++ b/Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs @@ -1,13 +1,16 @@ +using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; +using static Ryujinx.Core.OsHle.ErrorCode; + namespace Ryujinx.Core.OsHle.IpcServices.Am { - class ICommonStateGetter : IIpcService + class ICommonStateGetter : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ICommonStateGetter() { @@ -17,37 +20,31 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am { 1, ReceiveMessage }, { 5, GetOperationMode }, { 6, GetPerformanceMode }, - { 9, GetCurrentFocusState }, + { 9, GetCurrentFocusState } }; } - private enum FocusState - { - InFocus = 1, - OutOfFocus = 2 - } - - private enum OperationMode - { - Handheld = 0, - Docked = 1 - } - public long GetEventHandle(ServiceCtx Context) { - Context.ResponseData.Write(0L); + KEvent Event = Context.Process.AppletState.MessageEvent; + + int Handle = Context.Process.HandleTable.OpenHandle(Event); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); return 0; } public long ReceiveMessage(ServiceCtx Context) { - //Program expects 0xF at 0x17ae70 on puyo sdk, - //otherwise runs on a infinite loop until it reads said value. - //What it means is still unknown. - Context.ResponseData.Write(0xfL); + if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message)) + { + return MakeError(ErrorModule.Am, AmErr.NoMessages); + } - return 0; //0x680; + Context.ResponseData.Write((int)Message); + + return 0; } public long GetOperationMode(ServiceCtx Context) @@ -66,7 +63,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am public long GetCurrentFocusState(ServiceCtx Context) { - Context.ResponseData.Write((byte)FocusState.InFocus); + Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState); return 0; } diff --git a/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs b/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs index 944e58d81e..445b57e28a 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IDebugFunctions : IIpcService + class IDebugFunctions : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IDebugFunctions() { diff --git a/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs b/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs index 979e842a69..599562424e 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IDisplayController : IIpcService + class IDisplayController : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IDisplayController() { diff --git a/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs b/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs index 9f5b5e69c1..02da315619 100644 --- a/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs +++ b/Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class ILibraryAppletCreator : IIpcService + class ILibraryAppletCreator : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ILibraryAppletCreator() { diff --git a/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs b/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs index 403e4072d3..c5865009fb 100644 --- a/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs +++ b/Ryujinx.Core/OsHle/Services/Am/ISelfController.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class ISelfController : IIpcService + class ISelfController : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ISelfController() { diff --git a/Ryujinx.Core/OsHle/Services/Am/IStorage.cs b/Ryujinx.Core/OsHle/Services/Am/IStorage.cs index 375b960b1b..8f99ea7d03 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IStorage.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IStorage.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IStorage : IIpcService + class IStorage : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public byte[] Data { get; private set; } diff --git a/Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs b/Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs index 6d83e6f94f..096183ed2c 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs @@ -5,11 +5,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IStorageAccessor : IIpcService + class IStorageAccessor : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private IStorage Storage; diff --git a/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs b/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs index ddc73bced0..a830f2635a 100644 --- a/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs +++ b/Ryujinx.Core/OsHle/Services/Am/IWindowController.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Am { - class IWindowController : IIpcService + class IWindowController : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IWindowController() { diff --git a/Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs b/Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs new file mode 100644 index 0000000000..4c91e54a04 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + enum MessageInfo + { + FocusStateChanged = 0xf, + OperationModeChanged = 0x1e, + PerformanceModeChanged = 0x1f + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/OperationMode.cs b/Ryujinx.Core/OsHle/Services/Am/OperationMode.cs new file mode 100644 index 0000000000..7103742f25 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/Am/OperationMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Core.OsHle.IpcServices.Am +{ + enum OperationMode + { + Handheld = 0, + Docked = 1 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs b/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs index b60c93dd5e..255f74e62a 100644 --- a/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs +++ b/Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Am { - class ServiceAppletOE : IIpcService + class ServiceAppletOE : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceAppletOE() { diff --git a/Ryujinx.Core/OsHle/Services/Apm/ISession.cs b/Ryujinx.Core/OsHle/Services/Apm/ISession.cs index 500f7596cd..dd06e2c9da 100644 --- a/Ryujinx.Core/OsHle/Services/Apm/ISession.cs +++ b/Ryujinx.Core/OsHle/Services/Apm/ISession.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Apm { - class ISession : IIpcService + class ISession : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ISession() { diff --git a/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs b/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs index d6c0400acf..d75262160c 100644 --- a/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs +++ b/Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Apm { - class ServiceApm : IIpcService + class ServiceApm : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceApm() { diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs index 863c9a27f6..b8aa0a6eaf 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs @@ -5,11 +5,11 @@ using System.Text; namespace Ryujinx.Core.OsHle.IpcServices.Aud { - class IAudioDevice : IIpcService + class IAudioDevice : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IAudioDevice() { diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs index 8cd013f8b9..9549eb5710 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs @@ -7,17 +7,19 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Aud { - class IAudioOut : IIpcService, IDisposable + class IAudioOut : IpcService, IDisposable { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private IAalOutput AudioOut; + private KEvent ReleaseEvent; + private int Track; - public IAudioOut(IAalOutput AudioOut, int Track) + public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track) { m_Commands = new Dictionary() { @@ -32,8 +34,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud { 8, GetReleasedAudioOutBufferEx } }; - this.AudioOut = AudioOut; - this.Track = Track; + this.AudioOut = AudioOut; + this.ReleaseEvent = ReleaseEvent; + this.Track = Track; } public long GetAudioOutState(ServiceCtx Context) @@ -77,7 +80,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud public long RegisterBufferEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); + int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -143,6 +146,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud if (Disposing) { AudioOut.CloseTrack(Track); + + ReleaseEvent.Dispose(); } } } diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs index 4d29371fbd..68fe0f4cdf 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs @@ -1,14 +1,17 @@ using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; +using System; using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Aud { - class IAudioRenderer : IIpcService + class IAudioRenderer : IpcService, IDisposable { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent UpdateEvent; public IAudioRenderer() { @@ -19,6 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud { 6, StopAudioRenderer }, { 7, QuerySystemEvent } }; + + UpdateEvent = new KEvent(); } public long RequestUpdateAudioRenderer(ServiceCtx Context) @@ -41,6 +46,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud Context.Memory.WriteInt32(Position + Offset, 5); } + //TODO: We shouldn't be signaling this here. + UpdateEvent.Handle.Set(); + return 0; } @@ -56,11 +64,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud public long QuerySystemEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); + int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); return 0; } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + UpdateEvent.Dispose(); + } + } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs index 19f23d1c7c..5064398c92 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs @@ -1,18 +1,17 @@ using ChocolArm64.Memory; using Ryujinx.Audio; +using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; using System.Text; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Aud { - class ServiceAudOut : IIpcService + class ServiceAudOut : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceAudOut() { @@ -73,9 +72,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud Channels = 2; } - int Track = AudioOut.OpenTrack(SampleRate, Channels, out AudioFormat Format); + KEvent ReleaseEvent = new KEvent(); - MakeObject(Context, new IAudioOut(AudioOut, Track)); + ReleaseCallback Callback = () => + { + ReleaseEvent.Handle.Set(); + }; + + int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format); + + MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track)); Context.ResponseData.Write(SampleRate); Context.ResponseData.Write(Channels); diff --git a/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs index c3a0a8b436..8c7d95257c 100644 --- a/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs +++ b/Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Aud { - class ServiceAudRen : IIpcService + class ServiceAudRen : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceAudRen() { diff --git a/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs b/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs index 680e8405cf..825b3b2717 100644 --- a/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs +++ b/Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs @@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd public Socket Handle; } - class ServiceBsd : IIpcService + class ServiceBsd : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private List Sockets = new List(); diff --git a/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs b/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs index e3e03da855..f5497f38d4 100644 --- a/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs +++ b/Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Friend { - class IFriendService : IIpcService + class IFriendService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IFriendService() { diff --git a/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs b/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs index 674877f67f..43baf8bb23 100644 --- a/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs +++ b/Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Friend { - class ServiceFriend : IIpcService + class ServiceFriend : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceFriend() { diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs index 54dbec746b..6563c6aa13 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs @@ -7,13 +7,13 @@ using System.Text; namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { - class IDirectory : IIpcService, IDisposable + class IDirectory : IpcService, IDisposable { private const int DirectoryEntrySize = 0x310; private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private List DirectoryEntries; diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs index b997306122..7d01b22f81 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs @@ -6,11 +6,11 @@ using System.IO; namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { - class IFile : IIpcService, IDisposable + class IFile : IpcService, IDisposable { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private Stream BaseStream; diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs index 62bcb8e8b2..d5c2766e3d 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs @@ -5,15 +5,14 @@ using System.IO; using System.Text; using static Ryujinx.Core.OsHle.ErrorCode; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { - class IFileSystem : IIpcService + class IFileSystem : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private HashSet OpenPaths; diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs b/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs index 297461a047..d0f40333d4 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs @@ -5,11 +5,11 @@ using System.IO; namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { - class IStorage : IIpcService + class IStorage : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private Stream BaseStream; diff --git a/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs b/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs index 991f40272d..c6f23005a7 100644 --- a/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs +++ b/Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.FspSrv { - class ServiceFspSrv : IIpcService + class ServiceFspSrv : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceFspSrv() { diff --git a/Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs index f6596f4296..ff8291727a 100644 --- a/Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs +++ b/Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Hid { - class IActiveApplicationDeviceList : IIpcService + class IActiveApplicationDeviceList : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IActiveApplicationDeviceList() { diff --git a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs index ef437c022f..2b7e934e0c 100644 --- a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs +++ b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs @@ -4,11 +4,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Hid { - class IAppletResource : IIpcService + class IAppletResource : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private HSharedMem HidSharedMem; diff --git a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs index 6735c6ad2c..f15cbcfc34 100644 --- a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs +++ b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs @@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; using Ryujinx.Core.Input; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Hid { - class ServiceHid : IIpcService + class ServiceHid : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceHid() { diff --git a/Ryujinx.Core/OsHle/Services/IpcService.cs b/Ryujinx.Core/OsHle/Services/IpcService.cs new file mode 100644 index 0000000000..9dca811483 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/IpcService.cs @@ -0,0 +1,151 @@ +using Ryujinx.Core.OsHle.Ipc; +using Ryujinx.Core.OsHle.Handles; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.IpcServices +{ + abstract class IpcService : IIpcService + { + public abstract IReadOnlyDictionary Commands { get; } + + private IdDictionary DomainObjects; + + private int SelfId; + + private bool IsDomain; + + public IpcService() + { + DomainObjects = new IdDictionary(); + + SelfId = -1; + } + + public int ConvertToDomain() + { + if (SelfId == -1) + { + SelfId = DomainObjects.Add(this); + } + + IsDomain = true; + + return SelfId; + } + + public void ConvertToSession() + { + IsDomain = false; + } + + public void CallMethod(ServiceCtx Context) + { + IIpcService Service = this; + + if (IsDomain) + { + int DomainWord0 = Context.RequestData.ReadInt32(); + int DomainObjId = Context.RequestData.ReadInt32(); + + long Padding = Context.RequestData.ReadInt64(); + + int DomainCmd = DomainWord0 & 0xff; + + if (DomainCmd == 1) + { + Service = GetObject(DomainObjId); + + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + } + else if (DomainCmd == 2) + { + Delete(DomainObjId); + + Context.ResponseData.Write(0L); + + return; + } + else + { + throw new NotImplementedException($"Domain command: {DomainCmd}"); + } + } + + long SfciMagic = Context.RequestData.ReadInt64(); + int CommandId = (int)Context.RequestData.ReadInt64(); + + if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest)) + { + Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin); + + Logging.Trace($"{Service.GetType().Name}: {ProcessRequest.Method.Name}"); + + long Result = ProcessRequest(Context); + + if (IsDomain) + { + foreach (int Id in Context.Response.ResponseObjIds) + { + Context.ResponseData.Write(Id); + } + + Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin); + + Context.ResponseData.Write(Context.Response.ResponseObjIds.Count); + } + + Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin); + + Context.ResponseData.Write(IpcMagic.Sfco); + Context.ResponseData.Write(Result); + } + else + { + throw new NotImplementedException($"{Service.GetType().Name}: {CommandId}"); + } + } + + protected static void MakeObject(ServiceCtx Context, IpcService Obj) + { + IpcService Service = Context.Session.Service; + + if (Service.IsDomain) + { + Context.Response.ResponseObjIds.Add(Service.Add(Obj)); + } + else + { + KSession Session = new KSession(Obj); + + int Handle = Context.Process.HandleTable.OpenHandle(Session); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + } + } + + private int Add(IIpcService Obj) + { + return DomainObjects.Add(Obj); + } + + private bool Delete(int Id) + { + object Obj = DomainObjects.Delete(Id); + + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + + return Obj != null; + } + + private IIpcService GetObject(int Id) + { + return DomainObjects.GetData(Id); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs b/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs index 8ef9f3c6dd..c3f5b035ac 100644 --- a/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs +++ b/Ryujinx.Core/OsHle/Services/Lm/ILogger.cs @@ -7,11 +7,11 @@ using System.Text; namespace Ryujinx.Core.OsHle.IpcServices.Lm { - class ILogger : IIpcService + class ILogger : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ILogger() { diff --git a/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs b/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs index ca3fe35e83..e23ff56595 100644 --- a/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs +++ b/Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Lm { - class ServiceLm : IIpcService + class ServiceLm : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceLm() { @@ -21,8 +19,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm public long Initialize(ServiceCtx Context) { - Context.Session.Initialize(); - MakeObject(Context, new ILogger()); return 0; diff --git a/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs b/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs index c31ee36b20..abd1cc20fc 100644 --- a/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs +++ b/Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Nifm { - class IGeneralService : IIpcService + class IGeneralService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IGeneralService() { diff --git a/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs b/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs index 6110e5fbe2..1e1f13e68f 100644 --- a/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs +++ b/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs @@ -1,13 +1,17 @@ +using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; +using System; using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Nifm { - class IRequest : IIpcService + class IRequest : IpcService, IDisposable { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent Event; public IRequest() { @@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm { 1, GetResult }, { 2, GetSystemEventReadableHandles } }; + + Event = new KEvent(); } - // -> i32 public long GetRequestState(ServiceCtx Context) { Context.ResponseData.Write(0); @@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm //GetSystemEventReadableHandles() -> (KObject, KObject) public long GetSystemEventReadableHandles(ServiceCtx Context) { - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); + //FIXME: Is this supposed to return 2 events? + int Handle = Context.Process.HandleTable.OpenHandle(Event); - //Todo: Stub + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); return 0; } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Event.Dispose(); + } + } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs b/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs index 7e183389b2..b3602e9c49 100644 --- a/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs +++ b/Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Nifm { - class ServiceNifm : IIpcService + class ServiceNifm : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceNifm() { diff --git a/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs b/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs index 720baa6ec2..acdb92cf13 100644 --- a/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs +++ b/Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Ns { - class ServiceNs : IIpcService + class ServiceNs : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceNs() { diff --git a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs index 67ad44919a..ef223772f5 100644 --- a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs +++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Utilities; using Ryujinx.Graphics.Gpu; @@ -7,20 +8,22 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.NvServices { - class ServiceNvDrv : IIpcService + class ServiceNvDrv : IpcService, IDisposable { private delegate long ServiceProcessIoctl(ServiceCtx Context); private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds; - private IdDictionary Fds; + public static GlobalStateTable Fds { get; private set; } - private IdDictionary NvMaps; - private IdDictionary NvMapsById; + public static GlobalStateTable NvMaps { get; private set; } + public static GlobalStateTable NvMapsById { get; private set; } + + private KEvent Event; public ServiceNvDrv() { @@ -64,10 +67,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices { ("/dev/nvmap", 0x010e), NvMapIocGetId }, }; - Fds = new IdDictionary(); + Event = new KEvent(); + } - NvMaps = new IdDictionary(); - NvMapsById = new IdDictionary(); + static ServiceNvDrv() + { + Fds = new GlobalStateTable(); + + NvMaps = new GlobalStateTable(); + NvMapsById = new GlobalStateTable(); } public long Open(ServiceCtx Context) @@ -76,7 +84,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); - int Fd = Fds.Add(new NvFd(Name)); + int Fd = Fds.Add(Context.Process, new NvFd(Name)); Context.ResponseData.Write(Fd); Context.ResponseData.Write(0); @@ -89,7 +97,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Fd = Context.RequestData.ReadInt32(); int Cmd = Context.RequestData.ReadInt32() & 0xffff; - NvFd FdData = Fds.GetData(Fd); + NvFd FdData = Fds.GetData(Context.Process, Fd); long Position = Context.Request.GetSendBuffPtr(); @@ -109,7 +117,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices { int Fd = Context.RequestData.ReadInt32(); - Fds.Delete(Fd); + Fds.Delete(Context.Process, Fd); Context.ResponseData.Write(0); @@ -131,7 +139,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Fd = Context.RequestData.ReadInt32(); int EventId = Context.RequestData.ReadInt32(); - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe); + //TODO: Use Fd/EventId, different channels have different events. + int Handle = Context.Process.HandleTable.OpenHandle(Event); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); Context.ResponseData.Write(0); @@ -203,7 +214,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - NvMap Map = NvMaps.GetData(Handle); + NvMap Map = NvMaps.GetData(Context.Process, Handle); if (Map == null) { @@ -550,9 +561,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices NvMap Map = new NvMap() { Size = Size }; - Map.Handle = NvMaps.Add(Map); + Map.Handle = NvMaps.Add(Context.Process, Map); - Map.Id = NvMapsById.Add(Map); + Map.Id = NvMapsById.Add(Context.Process, Map); Context.Memory.WriteInt32(Position + 4, Map.Handle); @@ -567,7 +578,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Id = Context.Memory.ReadInt32(Position); - NvMap Map = NvMapsById.GetData(Id); + NvMap Map = NvMapsById.GetData(Context.Process, Id); if (Map == null) { @@ -594,7 +605,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices byte Kind = (byte)Reader.ReadInt64(); long Addr = Reader.ReadInt64(); - NvMap Map = NvMaps.GetData(Handle); + NvMap Map = NvMaps.GetData(Context.Process, Handle); if (Map == null) { @@ -620,7 +631,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Handle = Reader.ReadInt32(); int Padding = Reader.ReadInt32(); - NvMap Map = NvMaps.GetData(Handle); + NvMap Map = NvMaps.GetData(Context.Process, Handle); if (Map == null) { @@ -645,7 +656,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Handle = Reader.ReadInt32(); int Param = Reader.ReadInt32(); - NvMap Map = NvMaps.GetData(Handle); + NvMap Map = NvMaps.GetData(Context.Process, Handle); if (Map == null) { @@ -675,7 +686,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices int Handle = Context.Memory.ReadInt32(Position + 4); - NvMap Map = NvMaps.GetData(Handle); + NvMap Map = NvMaps.GetData(Context.Process, Handle); if (Map == null) { @@ -689,9 +700,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices return 0; } - public NvMap GetNvMap(int Handle) + public void Dispose() { - return NvMaps.GetData(Handle); + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Event.Dispose(); + } } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ObjHelper.cs b/Ryujinx.Core/OsHle/Services/ObjHelper.cs deleted file mode 100644 index 89d986aeb0..0000000000 --- a/Ryujinx.Core/OsHle/Services/ObjHelper.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Ryujinx.Core.OsHle.Handles; -using Ryujinx.Core.OsHle.Ipc; - -namespace Ryujinx.Core.OsHle.IpcServices -{ - static class ObjHelper - { - public static void MakeObject(ServiceCtx Context, object Obj) - { - if (Context.Session is HDomain Dom) - { - Context.Response.ResponseObjIds.Add(Dom.Add(Obj)); - } - else - { - HSessionObj HndData = new HSessionObj(Context.Session, Obj); - - int VHandle = Context.Process.HandleTable.OpenHandle(HndData); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs b/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs index 4eb92d31d5..45216864d2 100644 --- a/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs +++ b/Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Pctl { - class IParentalControlService : IIpcService + class IParentalControlService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IParentalControlService() { diff --git a/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs b/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs index 2d5e22a462..b648d184c8 100644 --- a/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs +++ b/Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Pctl { - class ServicePctl : IIpcService + class ServicePctl : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServicePctl() { diff --git a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs index 9a61779934..55637eac19 100644 --- a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs +++ b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Pl { - class ServicePl : IIpcService + class ServicePl : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServicePl() { diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs new file mode 100644 index 0000000000..9f43cdf003 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs @@ -0,0 +1,119 @@ +using Ryujinx.Core.OsHle.IpcServices.Acc; +using Ryujinx.Core.OsHle.IpcServices.Am; +using Ryujinx.Core.OsHle.IpcServices.Apm; +using Ryujinx.Core.OsHle.IpcServices.Aud; +using Ryujinx.Core.OsHle.IpcServices.Bsd; +using Ryujinx.Core.OsHle.IpcServices.Friend; +using Ryujinx.Core.OsHle.IpcServices.FspSrv; +using Ryujinx.Core.OsHle.IpcServices.Hid; +using Ryujinx.Core.OsHle.IpcServices.Lm; +using Ryujinx.Core.OsHle.IpcServices.Nifm; +using Ryujinx.Core.OsHle.IpcServices.Ns; +using Ryujinx.Core.OsHle.IpcServices.NvServices; +using Ryujinx.Core.OsHle.IpcServices.Pctl; +using Ryujinx.Core.OsHle.IpcServices.Pl; +using Ryujinx.Core.OsHle.IpcServices.Set; +using Ryujinx.Core.OsHle.IpcServices.Sfdnsres; +using Ryujinx.Core.OsHle.IpcServices.Sm; +using Ryujinx.Core.OsHle.IpcServices.Ssl; +using Ryujinx.Core.OsHle.IpcServices.Time; +using Ryujinx.Core.OsHle.IpcServices.Vi; +using System; + +namespace Ryujinx.Core.OsHle.IpcServices +{ + static class ServiceFactory + { + public static IpcService MakeService(string Name) + { + switch (Name) + { + case "acc:u0": + return new ServiceAcc(); + + case "aoc:u": + return new ServiceNs(); + + case "apm": + return new ServiceApm(); + + case "apm:p": + return new ServiceApm(); + + case "appletOE": + return new ServiceAppletOE(); + + case "audout:u": + return new ServiceAudOut(); + + case "audren:u": + return new ServiceAudRen(); + + case "bsd:s": + return new ServiceBsd(); + + case "bsd:u": + return new ServiceBsd(); + + case "friend:a": + return new ServiceFriend(); + + case "fsp-srv": + return new ServiceFspSrv(); + + case "hid": + return new ServiceHid(); + + case "lm": + return new ServiceLm(); + + case "nifm:u": + return new ServiceNifm(); + + case "nvdrv": + return new ServiceNvDrv(); + + case "nvdrv:a": + return new ServiceNvDrv(); + + case "pctl:a": + return new ServicePctl(); + + case "pl:u": + return new ServicePl(); + + case "set": + return new ServiceSet(); + + case "set:sys": + return new ServiceSetSys(); + + case "sfdnsres": + return new ServiceSfdnsres(); + + case "sm:": + return new ServiceSm(); + + case "ssl": + return new ServiceSsl(); + + case "time:s": + return new ServiceTime(); + + case "time:u": + return new ServiceTime(); + + case "vi:m": + return new ServiceVi(); + + case "vi:s": + return new ServiceVi(); + + case "vi:u": + return new ServiceVi(); + } + + throw new NotImplementedException(Name); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs index c60e1712aa..558243578a 100644 --- a/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs @@ -5,11 +5,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Set { - class ServiceSet : IIpcService + class ServiceSet : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceSet() { diff --git a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs index dee6573d35..1d6afc4fc5 100644 --- a/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs +++ b/Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Set { - class ServiceSetSys : IIpcService + class ServiceSetSys : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceSetSys() { diff --git a/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs b/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs index f110ae736f..1f68558ed6 100644 --- a/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs +++ b/Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres { - class ServiceSfdnsres : IIpcService + class ServiceSfdnsres : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceSfdnsres() { diff --git a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs index cb745e3738..770227d52d 100644 --- a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs +++ b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs @@ -4,11 +4,13 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Sm { - class ServiceSm : IIpcService + class ServiceSm : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; + + private bool IsInitialized; public ServiceSm() { @@ -23,7 +25,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm public long Initialize(ServiceCtx Context) { - Context.Session.Initialize(); + IsInitialized = true; return 0; } @@ -31,7 +33,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm public long GetService(ServiceCtx Context) { //Only for kernel version > 3.0.0. - if (!Context.Session.IsInitialized) + if (!IsInitialized) { //return SmNotInitialized; } @@ -55,7 +57,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm return 0; } - HSession Session = new HSession(Context.Process.Services.GetService(Name)); + KSession Session = new KSession(ServiceFactory.MakeService(Name)); int Handle = Context.Process.HandleTable.OpenHandle(Session); diff --git a/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs b/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs index 23934b1405..b9513a864a 100644 --- a/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs +++ b/Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Ssl { - class ServiceSsl : IIpcService + class ServiceSsl : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceSsl() { diff --git a/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs b/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs index d20e4378ad..91d78664af 100644 --- a/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs +++ b/Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Time { - class ISteadyClock : IIpcService + class ISteadyClock : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ISteadyClock() { diff --git a/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs b/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs index 4d4493dad4..f7f710c8e2 100644 --- a/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs +++ b/Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs @@ -4,11 +4,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Time { - class ISystemClock : IIpcService + class ISystemClock : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); diff --git a/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs b/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs index d220824c56..63329ada79 100644 --- a/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs +++ b/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs @@ -4,11 +4,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Time { - class ITimeZoneService : IIpcService + class ITimeZoneService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); diff --git a/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs b/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs index 43f28bb80b..1f94793985 100644 --- a/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs +++ b/Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Time { - class ServiceTime : IIpcService + class ServiceTime : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceTime() { diff --git a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs index 0ff1f90993..62db23b408 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs @@ -1,19 +1,17 @@ using ChocolArm64.Memory; -using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; using System.IO; using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; namespace Ryujinx.Core.OsHle.IpcServices.Vi { - class IApplicationDisplayService : IIpcService + class IApplicationDisplayService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; private IdDictionary Displays; @@ -145,7 +143,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { string Name = GetDisplayName(Context); - int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); + int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.VsyncEvent); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs index beccbe7d3f..4c34200609 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.IpcServices.Android; using Ryujinx.Graphics.Gal; @@ -7,11 +8,13 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Vi { - class IHOSBinderDriver : IIpcService, IDisposable + class IHOSBinderDriver : IpcService, IDisposable { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; + + private KEvent ReleaseEvent; private NvFlinger Flinger; @@ -24,7 +27,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { 2, GetNativeHandle } }; - Flinger = new NvFlinger(Renderer); + ReleaseEvent = new KEvent(); + + Flinger = new NvFlinger(Renderer, ReleaseEvent); } public long TransactParcel(ServiceCtx Context) @@ -56,7 +61,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi int Id = Context.RequestData.ReadInt32(); uint Unk = Context.RequestData.ReadUInt32(); - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); + int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); return 0; } @@ -70,6 +77,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi { if (Disposing) { + ReleaseEvent.Dispose(); + Flinger.Dispose(); } } diff --git a/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs index 69dbff47a9..6c7f36ff1d 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Vi { - class IManagerDisplayService : IIpcService + class IManagerDisplayService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public IManagerDisplayService() { diff --git a/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs index d87fcbf6ec..814ed7d1b8 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; namespace Ryujinx.Core.OsHle.IpcServices.Vi { - class ISystemDisplayService : IIpcService + class ISystemDisplayService : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ISystemDisplayService() { diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 5309dcabb7..3a7a2ee62d 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.IpcServices.NvServices; using Ryujinx.Graphics.Gal; using System; @@ -17,6 +18,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android private Dictionary<(string, int), ServiceProcessParcel> Commands; + private KEvent ReleaseEvent; + + private IGalRenderer Renderer; + private const int BufferQueueCount = 0x40; private const int BufferQueueMask = BufferQueueCount - 1; @@ -55,8 +60,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android public GbpBuffer Data; } - private IGalRenderer Renderer; - private BufferEntry[] BufferQueue; private ManualResetEvent WaitBufferFree; @@ -69,7 +72,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android private bool KeepRunning; - public NvFlinger(IGalRenderer Renderer) + public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent) { Commands = new Dictionary<(string, int), ServiceProcessParcel>() { @@ -83,8 +86,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect }, { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } }; - - this.Renderer = Renderer; + + this.Renderer = Renderer; + this.ReleaseEvent = ReleaseEvent; BufferQueue = new BufferEntry[0x40]; @@ -293,6 +297,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android BufferQueue[Slot].State = BufferState.Free; + ReleaseEvent.Handle.Set(); + WaitBufferFree.Set(); return; @@ -377,6 +383,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android Interlocked.Decrement(ref RenderQueueCount); + ReleaseEvent.Handle.Set(); + lock (WaitBufferFree) { WaitBufferFree.Set(); @@ -397,9 +405,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android NvMapHandle = BitConverter.ToInt32(RawValue, 0); } - ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv"); - - return NvDrv.GetNvMap(NvMapHandle); + return ServiceNvDrv.NvMaps.GetData(Context.Process, NvMapHandle); } private int GetFreeSlotBlocking(int Width, int Height) diff --git a/Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs b/Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs index 2c3dd2a3c8..360cb6fafe 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs @@ -1,15 +1,13 @@ using Ryujinx.Core.OsHle.Ipc; using System.Collections.Generic; -using static Ryujinx.Core.OsHle.IpcServices.ObjHelper; - namespace Ryujinx.Core.OsHle.IpcServices.Vi { - class ServiceVi : IIpcService + class ServiceVi : IpcService { private Dictionary m_Commands; - public IReadOnlyDictionary Commands => m_Commands; + public override IReadOnlyDictionary Commands => m_Commands; public ServiceVi() { diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs index 9417473cf5..96bef5e474 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs @@ -3,6 +3,7 @@ using ChocolArm64.State; using Ryujinx.Core.OsHle.Exceptions; using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Ipc; +using Ryujinx.Core.OsHle.IpcServices; using System; using System.Threading; @@ -34,7 +35,28 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - Process.HandleTable.CloseHandle(Handle); + object Obj = Process.HandleTable.CloseHandle(Handle); + + if (Obj == null) + { + Logging.Warn($"Tried to CloseHandle on 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; } @@ -43,25 +65,78 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - //TODO: Implement events. + KEvent Event = Process.HandleTable.GetData(Handle); - ThreadState.X0 = 0; + if (Event != null) + { + Event.Handle.Reset(); + + ThreadState.X0 = 0; + } + else + { + Logging.Warn($"Tried to ResetSignal on invalid event handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + } } private void SvcWaitSynchronization(AThreadState ThreadState) { - long HandlesPtr = (long)ThreadState.X0; + long HandlesPtr = (long)ThreadState.X1; int HandlesCount = (int)ThreadState.X2; long Timeout = (long)ThreadState.X3; - //TODO: Implement events. + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + WaitHandle[] Handles = new WaitHandle[HandlesCount]; + + for (int Index = 0; Index < HandlesCount; Index++) + { + int Handle = Memory.ReadInt32(HandlesPtr + Index * 4); + + KSynchronizationObject SyncObj = Process.HandleTable.GetData(Handle); + + if (SyncObj == null) + { + Logging.Warn($"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + + return; + } + + Handles[Index] = SyncObj.Handle; + } Process.Scheduler.Suspend(CurrThread.ProcessorId); + + int HandleIndex; + + ulong Result = 0; + + if (Timeout != -1) + { + HandleIndex = WaitHandle.WaitAny(Handles, (int)(Timeout / 1000000)); + + if (HandleIndex == WaitHandle.WaitTimeout) + { + Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); + } + } + else + { + HandleIndex = WaitHandle.WaitAny(Handles); + } + Process.Scheduler.Resume(CurrThread); - ThreadState.X0 = 0; + ThreadState.X0 = Result; + + if (Result == 0) + { + ThreadState.X1 = (ulong)HandleIndex; + } } private void SvcGetSystemTick(AThreadState ThreadState) @@ -78,8 +153,7 @@ namespace Ryujinx.Core.OsHle.Svc //TODO: Validate that app has perms to access the service, and that the service //actually exists, return error codes otherwise. - - HSession Session = new HSession(Process.Services.GetService(Name)); + KSession Session = new KSession(ServiceFactory.MakeService(Name)); ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); @@ -89,65 +163,46 @@ namespace Ryujinx.Core.OsHle.Svc private void SvcSendSyncRequest(AThreadState ThreadState) { - SendSyncRequest(ThreadState, false); + SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0); } private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState) { - SendSyncRequest(ThreadState, true); + SendSyncRequest( + ThreadState, + (long)ThreadState.X0, + (long)ThreadState.X1, + (int)ThreadState.X2); } - private void SendSyncRequest(AThreadState ThreadState, bool UserBuffer) + private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle) { - long CmdPtr = ThreadState.Tpidr; - long Size = 0x100; - int Handle = 0; - - if (UserBuffer) - { - CmdPtr = (long)ThreadState.X0; - Size = (long)ThreadState.X1; - Handle = (int)ThreadState.X2; - } - else - { - Handle = (int)ThreadState.X0; - } - - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - Process.Scheduler.Suspend(CurrThread.ProcessorId); + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); - HSession Session = Process.HandleTable.GetData(Handle); - - IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain); + KSession Session = Process.HandleTable.GetData(Handle); if (Session != null) { - IpcHandler.IpcCall( - Ns, - Process, - Memory, - Session, - Cmd, - ThreadState.ThreadId, - CmdPtr, - Handle); + Process.Scheduler.Suspend(CurrThread.ProcessorId); - byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); + IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr); + + IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr); + + Thread.Yield(); + + Process.Scheduler.Resume(CurrThread); ThreadState.X0 = 0; } else { - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidIpcReq); + Logging.Warn($"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!"); + + ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); } - - Thread.Yield(); - - Process.Scheduler.Resume(CurrThread); } private void SvcBreak(AThreadState ThreadState) diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs index 231ee2a237..77cef44cc7 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThread.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs @@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - HThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { @@ -53,16 +53,18 @@ namespace Ryujinx.Core.OsHle.Svc private void SvcExitThread(AThreadState ThreadState) { - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + CurrThread.Thread.StopExecution(); + + CurrThread.Handle.Set(); } private void SvcSleepThread(AThreadState ThreadState) { ulong NanoSecs = ThreadState.X0; - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); if (NanoSecs == 0) { @@ -78,7 +80,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X1; - HThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { @@ -91,10 +93,10 @@ namespace Ryujinx.Core.OsHle.Svc private void SvcSetThreadPriority(AThreadState ThreadState) { + int Prio = (int)ThreadState.X0; int Handle = (int)ThreadState.X1; - int Prio = (int)ThreadState.X0; - HThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { @@ -117,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Svc { int Handle = (int)ThreadState.X0; - HThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetData(Handle); if (Thread != null) { diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs index 38356073e6..318688b853 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc long MutexAddress = (long)ThreadState.X1; int RequestingThreadHandle = (int)ThreadState.X2; - HThread RequestingThread = Process.HandleTable.GetData(RequestingThreadHandle); + KThread RequestingThread = Process.HandleTable.GetData(RequestingThreadHandle); Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle); @@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc int ThreadHandle = (int)ThreadState.X2; long Timeout = (long)ThreadState.X3; - HThread Thread = Process.HandleTable.GetData(ThreadHandle); + KThread Thread = Process.HandleTable.GetData(ThreadHandle); Mutex M = new Mutex(Process, MutexAddress, ThreadHandle); @@ -72,7 +72,7 @@ namespace Ryujinx.Core.OsHle.Svc long CondVarAddress = (long)ThreadState.X0; int Count = (int)ThreadState.X1; - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv)) { diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs index 92d78f4536..0df8b12602 100644 --- a/Ryujinx.Core/Switch.cs +++ b/Ryujinx.Core/Switch.cs @@ -14,10 +14,10 @@ namespace Ryujinx.Core internal NsGpu Gpu { get; private set; } - internal Horizon Os { get; private set; } - internal VirtualFileSystem VFs { get; private set; } + public Horizon Os { get; private set; } + public SystemSettings Settings { get; private set; } public PerformanceStatistics Statistics { get; private set; } @@ -40,12 +40,12 @@ namespace Ryujinx.Core this.AudioOut = AudioOut; - Gpu = new NsGpu(Renderer); - - Os = new Horizon(this); + Gpu = new NsGpu(Renderer); VFs = new VirtualFileSystem(); + Os = new Horizon(this); + Settings = new SystemSettings(); Statistics = new PerformanceStatistics(); diff --git a/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs b/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs index 6543b1d1d8..652f3e7517 100644 --- a/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs +++ b/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu { private NsGpu Gpu; - private int[] Registers; + private uint[] Registers; public NsGpuEngine[] SubChannels; @@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.Gpu { this.Gpu = Gpu; - Registers = new int[0x1000]; + Registers = new uint[0x1000]; SubChannels = new NsGpuEngine[8]; @@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Gpu { if (Entry.Arguments.Count == 1) { - SetRegister(Entry.Register, Entry.Arguments[0]); + SetRegister(Entry.Register, (uint)Entry.Arguments[0]); } switch (Entry.Register) @@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu case NsGpuRegister._3dVertexArray0Fetch: SendVertexBuffers(Memory); break; - + case NsGpuRegister._3dCbData0: if (GetRegister(NsGpuRegister._3dCbPos) == 0x20) { @@ -62,6 +62,22 @@ namespace Ryujinx.Graphics.Gpu case NsGpuRegister._3dQueryGet: HasQuery = true; break; + + case NsGpuRegister._3dSetShader: + uint ShaderPrg = (uint)Entry.Arguments[0]; + uint ShaderId = (uint)Entry.Arguments[1]; + uint CodeAddr = (uint)Entry.Arguments[2]; + uint ShaderType = (uint)Entry.Arguments[3]; + uint CodeEnd = (uint)Entry.Arguments[4]; + + SendShader( + Memory, + ShaderPrg, + ShaderId, + CodeAddr, + ShaderType, + CodeEnd); + break; } } @@ -71,10 +87,10 @@ namespace Ryujinx.Graphics.Gpu (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 | (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0; - int Seq = GetRegister(NsGpuRegister._3dQuerySequence); - int Get = GetRegister(NsGpuRegister._3dQueryGet); + uint Seq = GetRegister(NsGpuRegister._3dQuerySequence); + uint Get = GetRegister(NsGpuRegister._3dQueryGet); - int Mode = Get & 3; + uint Mode = Get & 3; if (Mode == 0) { @@ -85,7 +101,7 @@ namespace Ryujinx.Graphics.Gpu { Gpu.Renderer.QueueAction(delegate() { - Memory.WriteInt32(Position, Seq); + Memory.WriteUInt32(Position, Seq); }); } } @@ -119,13 +135,13 @@ namespace Ryujinx.Graphics.Gpu { byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, Size); - int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff; + int Stride = (int)GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff; List Attribs = new List(); for (int Attr = 0; Attr < 16; Attr++) { - int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4); + int Packed = (int)GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4); GalVertexAttrib Attrib = new GalVertexAttrib(Attr, (Packed >> 0) & 0x1f, @@ -154,10 +170,10 @@ namespace Ryujinx.Graphics.Gpu long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 | (long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0; - int CbData = GetRegister(NsGpuRegister._3dCbData0); + uint CbData = GetRegister(NsGpuRegister._3dCbData0); - int TicIndex = (CbData >> 0) & 0xfffff; - int TscIndex = (CbData >> 20) & 0xfff; //I guess? + uint TicIndex = (CbData >> 0) & 0xfffff; + uint TscIndex = (CbData >> 20) & 0xfff; //I guess? TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20); @@ -198,6 +214,19 @@ namespace Ryujinx.Graphics.Gpu } } + private void SendShader( + AMemory Memory, + uint ShaderPrg, + uint ShaderId, + uint CodeAddr, + uint ShaderType, + uint CodeEnd) + { + long CodePos = Gpu.MemoryMgr.GetCpuAddr(CodeAddr); + + byte[] Data = AMemoryHelper.ReadBytes(Memory, CodePos, 0x300); + } + private static byte[] GetDecodedTexture( AMemory Memory, NsGpuTextureFormat Format, @@ -263,12 +292,12 @@ namespace Ryujinx.Graphics.Gpu return Data; } - public int GetRegister(NsGpuRegister Register) + public uint GetRegister(NsGpuRegister Register) { return Registers[((int)Register >> 2) & 0xfff]; } - public void SetRegister(NsGpuRegister Register, int Value) + public void SetRegister(NsGpuRegister Register, uint Value) { Registers[((int)Register >> 2) & 0xfff] = Value; } diff --git a/Ryujinx.Graphics/Gpu/NsGpuRegister.cs b/Ryujinx.Graphics/Gpu/NsGpuRegister.cs index 319e2c01f6..4642e68d67 100644 --- a/Ryujinx.Graphics/Gpu/NsGpuRegister.cs +++ b/Ryujinx.Graphics/Gpu/NsGpuRegister.cs @@ -89,5 +89,6 @@ namespace Ryujinx.Graphics.Gpu _3dCbData13 = 0x23c4, _3dCbData14 = 0x23c8, _3dCbData15 = 0x23cc, + _3dSetShader = 0x3890 } } \ No newline at end of file diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index b0dca81b77..3bcef92183 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -181,6 +181,8 @@ namespace Ryujinx SwapBuffers(); Ns.Statistics.EndSystemFrame(); + + Ns.Os.SignalVsync(); } protected override void OnResize(EventArgs e)