[WIP] Add support for events (#60)

* Add support for events, move concept of domains to IpcService

* Support waiting for KThread, remove some test code, other tweaks

* Use move handle on NIFM since I can't test that now, it's better to leave it how it was
This commit is contained in:
gdkchan 2018-03-19 15:58:46 -03:00 committed by GitHub
parent 4940cf0ea5
commit 4314a8f3e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
101 changed files with 1120 additions and 836 deletions

View file

@ -2,7 +2,11 @@ namespace Ryujinx.Audio
{ {
public interface IAalOutput 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); void CloseTrack(int Track);

View file

@ -3,6 +3,7 @@ using OpenTK.Audio.OpenAL;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.Audio.OpenAL namespace Ryujinx.Audio.OpenAL
{ {
@ -22,20 +23,27 @@ namespace Ryujinx.Audio.OpenAL
public ALFormat Format { get; private set; } public ALFormat Format { get; private set; }
private ReleaseCallback Callback;
public PlaybackState State { get; set; } public PlaybackState State { get; set; }
private bool ShouldCallReleaseCallback;
private ConcurrentDictionary<long, int> Buffers; private ConcurrentDictionary<long, int> Buffers;
private Queue<long> QueuedTagsQueue; private Queue<long> QueuedTagsQueue;
private Queue<long> ReleasedTagsQueue; private Queue<long> ReleasedTagsQueue;
private int LastReleasedCount;
private bool Disposed; private bool Disposed;
public Track(int SampleRate, ALFormat Format) public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
{ {
this.SampleRate = SampleRate; this.SampleRate = SampleRate;
this.Format = Format; this.Format = Format;
this.Callback = Callback;
State = PlaybackState.Stopped; State = PlaybackState.Stopped;
@ -109,11 +117,42 @@ namespace Ryujinx.Audio.OpenAL
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount); AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
if (ReleasedCount > 0) if (ReleasedCount > 0)
{ {
AL.SourceUnqueueBuffers(SourceId, ReleasedCount); 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() private void SyncQueuedTags()
{ {
@ -156,18 +195,46 @@ namespace Ryujinx.Audio.OpenAL
private ConcurrentDictionary<int, Track> Tracks; private ConcurrentDictionary<int, Track> Tracks;
private Thread AudioPollerThread;
private bool KeepPolling;
public OpenALAudioOut() public OpenALAudioOut()
{ {
Context = new AudioContext(); Context = new AudioContext();
Tracks = new ConcurrentDictionary<int, Track>(); Tracks = new ConcurrentDictionary<int, Track>();
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; 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++) for (int Id = 0; Id < MaxTracks; Id++)
{ {
@ -292,5 +359,7 @@ namespace Ryujinx.Audio.OpenAL
return PlaybackState.Stopped; return PlaybackState.Stopped;
} }
} }
} }

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Audio
{
public delegate void ReleaseCallback();
}

View file

@ -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<MessageInfo> Messages;
public FocusState FocusState { get; private set; }
public KEvent MessageEvent { get; private set; }
public AppletStateMgr()
{
Messages = new ConcurrentQueue<MessageInfo>();
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();
}
}
}
}

View file

@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle
private bool OwnsCondVarValue; private bool OwnsCondVarValue;
private List<HThread> WaitingThreads; private List<KThread> WaitingThreads;
public CondVar(Process Process, long CondVarAddress, long Timeout) public CondVar(Process Process, long CondVarAddress, long Timeout)
{ {
@ -21,10 +21,10 @@ namespace Ryujinx.Core.OsHle
this.CondVarAddress = CondVarAddress; this.CondVarAddress = CondVarAddress;
this.Timeout = Timeout; this.Timeout = Timeout;
WaitingThreads = new List<HThread>(); WaitingThreads = new List<KThread>();
} }
public bool WaitForSignal(HThread Thread) public bool WaitForSignal(KThread Thread)
{ {
int Count = Process.Memory.ReadInt32(CondVarAddress); int Count = Process.Memory.ReadInt32(CondVarAddress);
@ -66,7 +66,7 @@ namespace Ryujinx.Core.OsHle
return true; return true;
} }
public void SetSignal(HThread Thread, int Count) public void SetSignal(KThread Thread, int Count)
{ {
lock (WaitingThreads) lock (WaitingThreads)
{ {

View file

@ -1,12 +0,0 @@
namespace Ryujinx.Core.OsHle
{
class FileDesc
{
public string Name { get; private set; }
public FileDesc(string Name)
{
this.Name = Name;
}
}
}

View file

@ -0,0 +1,62 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle
{
class GlobalStateTable
{
private ConcurrentDictionary<Process, IdDictionary> DictByProcess;
public GlobalStateTable()
{
DictByProcess = new ConcurrentDictionary<Process, IdDictionary>();
}
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<T>(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.GetData<T>(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<object> DeleteProcess(Process Process)
{
if (DictByProcess.TryRemove(Process, out IdDictionary Dict))
{
return Dict.Clear();
}
return null;
}
}
}

View file

@ -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();
}
}
}
}
}
}

View file

@ -1,7 +0,0 @@
namespace Ryujinx.Core.OsHle.Handles
{
class HEvent
{
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}
}
}

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Core.OsHle.Handles
{
class KEvent : KSynchronizationObject { }
}

View file

@ -1,8 +1,8 @@
using System; using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.Handles namespace Ryujinx.Core.OsHle.Handles
{ {
class KProcessHandleTable : IDisposable class KProcessHandleTable
{ {
private IdDictionary Handles; private IdDictionary Handles;
@ -21,43 +21,14 @@ namespace Ryujinx.Core.OsHle.Handles
return Handles.GetData<T>(Handle); return Handles.GetData<T>(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); return Handles.Delete(Handle);
} }
public void Dispose() public ICollection<object> Clear()
{ {
Dispose(true); return Handles.Clear();
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
foreach (object Obj in Handles)
{
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
}
}
} }
} }
} }

View file

@ -5,15 +5,15 @@ using System.Threading;
namespace Ryujinx.Core.OsHle.Handles namespace Ryujinx.Core.OsHle.Handles
{ {
public class KProcessScheduler : IDisposable class KProcessScheduler : IDisposable
{ {
private class SchedulerThread : IDisposable private class SchedulerThread : IDisposable
{ {
public HThread Thread { get; private set; } public KThread Thread { get; private set; }
public AutoResetEvent WaitEvent { get; private set; } public AutoResetEvent WaitEvent { get; private set; }
public SchedulerThread(HThread Thread) public SchedulerThread(KThread Thread)
{ {
this.Thread = Thread; this.Thread = Thread;
@ -95,7 +95,7 @@ namespace Ryujinx.Core.OsHle.Handles
} }
} }
private ConcurrentDictionary<HThread, SchedulerThread> AllThreads; private ConcurrentDictionary<KThread, SchedulerThread> AllThreads;
private ThreadQueue[] WaitingToRun; private ThreadQueue[] WaitingToRun;
@ -105,7 +105,7 @@ namespace Ryujinx.Core.OsHle.Handles
public KProcessScheduler() public KProcessScheduler()
{ {
AllThreads = new ConcurrentDictionary<HThread, SchedulerThread>(); AllThreads = new ConcurrentDictionary<KThread, SchedulerThread>();
WaitingToRun = new ThreadQueue[4]; WaitingToRun = new ThreadQueue[4];
@ -119,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Handles
SchedLock = new object(); SchedLock = new object();
} }
public void StartThread(HThread Thread) public void StartThread(KThread Thread)
{ {
lock (SchedLock) lock (SchedLock)
{ {
@ -164,7 +164,7 @@ namespace Ryujinx.Core.OsHle.Handles
} }
} }
public void Resume(HThread CurrThread) public void Resume(KThread CurrThread)
{ {
SchedulerThread SchedThread; SchedulerThread SchedThread;
@ -183,7 +183,7 @@ namespace Ryujinx.Core.OsHle.Handles
TryResumingExecution(SchedThread); TryResumingExecution(SchedThread);
} }
public bool WaitForSignal(HThread Thread, int Timeout = -1) public bool WaitForSignal(KThread Thread, int Timeout = -1)
{ {
SchedulerThread SchedThread; SchedulerThread SchedThread;
@ -230,7 +230,7 @@ namespace Ryujinx.Core.OsHle.Handles
private void TryResumingExecution(SchedulerThread SchedThread) private void TryResumingExecution(SchedulerThread SchedThread)
{ {
HThread Thread = SchedThread.Thread; KThread Thread = SchedThread.Thread;
lock (SchedLock) lock (SchedLock)
{ {
@ -249,7 +249,7 @@ namespace Ryujinx.Core.OsHle.Handles
Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
} }
public void Yield(HThread Thread) public void Yield(KThread Thread)
{ {
SchedulerThread SchedThread; 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) lock (SchedLock)
{ {
foreach (HThread Thread in Threads) foreach (KThread Thread in Threads)
{ {
if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) 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}"; return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}";
} }

View file

@ -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();
}
}
}
}

View file

@ -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();
}
}
}
}

View file

@ -2,7 +2,7 @@ using ChocolArm64;
namespace Ryujinx.Core.OsHle.Handles namespace Ryujinx.Core.OsHle.Handles
{ {
public class HThread class KThread : KSynchronizationObject
{ {
public AThread Thread { get; private set; } public AThread Thread { get; private set; }
@ -11,7 +11,7 @@ namespace Ryujinx.Core.OsHle.Handles
public int ThreadId => Thread.ThreadId; 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.Thread = Thread;
this.ProcessorId = ProcessorId; this.ProcessorId = ProcessorId;

View file

@ -16,8 +16,10 @@ namespace Ryujinx.Core.OsHle
private ConcurrentDictionary<int, Process> Processes; private ConcurrentDictionary<int, Process> Processes;
internal HSharedMem HidSharedMem; internal HSharedMem HidSharedMem { get; private set; }
internal HSharedMem FontSharedMem; internal HSharedMem FontSharedMem { get; private set; }
internal KEvent VsyncEvent { get; private set; }
private Switch Ns; private Switch Ns;
@ -32,6 +34,8 @@ namespace Ryujinx.Core.OsHle
HidSharedMem = new HSharedMem(); HidSharedMem = new HSharedMem();
FontSharedMem = new HSharedMem(); FontSharedMem = new HSharedMem();
VsyncEvent = new KEvent();
} }
public void LoadCart(string ExeFsDir, string RomFsFile = null) public void LoadCart(string ExeFsDir, string RomFsFile = null)
@ -91,6 +95,8 @@ namespace Ryujinx.Core.OsHle
MainProcess.Run(IsNro); MainProcess.Run(IsNro);
} }
public void SignalVsync() => VsyncEvent.Handle.Set();
private Process MakeProcess() private Process MakeProcess()
{ {
Process Process; Process Process;
@ -109,9 +115,16 @@ namespace Ryujinx.Core.OsHle
Processes.TryAdd(ProcessId, Process); Processes.TryAdd(ProcessId, Process);
} }
InitializeProcess(Process);
return Process; return Process;
} }
private void InitializeProcess(Process Process)
{
Process.AppletState.SetFocus(true);
}
internal void ExitProcess(int ProcessId) internal void ExitProcess(int ProcessId)
{ {
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi) if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
@ -171,6 +184,8 @@ namespace Ryujinx.Core.OsHle
Process.StopAllThreadsAsync(); Process.StopAllThreadsAsync();
Process.Dispose(); Process.Dispose();
} }
VsyncEvent.Dispose();
} }
} }
} }

View file

@ -1,11 +1,10 @@
using System; using System;
using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Core.OsHle namespace Ryujinx.Core.OsHle
{ {
class IdDictionary : IEnumerable<object> class IdDictionary
{ {
private ConcurrentDictionary<int, object> Objs; private ConcurrentDictionary<int, object> Objs;
@ -39,18 +38,6 @@ namespace Ryujinx.Core.OsHle
throw new InvalidOperationException(); 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) public object GetData(int Id)
{ {
if (Objs.TryGetValue(Id, out object Data)) if (Objs.TryGetValue(Id, out object Data))
@ -71,31 +58,25 @@ namespace Ryujinx.Core.OsHle
return default(T); return default(T);
} }
public bool Delete(int Id) public object Delete(int Id)
{ {
if (Objs.TryRemove(Id, out object Obj)) if (Objs.TryRemove(Id, out object Obj))
{ {
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
FreeIdHint = Id; FreeIdHint = Id;
return true; return Obj;
} }
return false; return null;
} }
IEnumerator<object> IEnumerable<object>.GetEnumerator() public ICollection<object> Clear()
{ {
return Objs.Values.GetEnumerator(); ICollection<object> Values = Objs.Values;
}
IEnumerator IEnumerable.GetEnumerator() Objs.Clear();
{
return Objs.Values.GetEnumerator(); return Values;
} }
} }
} }

View file

@ -1,8 +0,0 @@
namespace Ryujinx.Core.OsHle.Ipc
{
enum IpcDomCmd
{
SendMsg = 1,
DeleteObj = 2
}
}

View file

@ -1,6 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices;
using System; using System;
using System.IO; using System.IO;
@ -8,20 +7,15 @@ namespace Ryujinx.Core.OsHle.Ipc
{ {
static class IpcHandler 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( public static void IpcCall(
Switch Ns, Switch Ns,
Process Process, Process Process,
AMemory Memory, AMemory Memory,
HSession Session, KSession Session,
IpcMessage Request, IpcMessage Request,
int ThreadId, long CmdPtr)
long CmdPtr,
int HndId)
{ {
IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request); IpcMessage Response = new IpcMessage();
using (MemoryStream Raw = new MemoryStream(Request.RawData)) using (MemoryStream Raw = new MemoryStream(Request.RawData))
{ {
@ -29,94 +23,25 @@ namespace Ryujinx.Core.OsHle.Ipc
if (Request.Type == IpcMessageType.Request) if (Request.Type == IpcMessageType.Request)
{ {
string ServiceName = Session.Service.GetType().Name; Response.Type = IpcMessageType.Response;
ServiceProcessRequest ProcReq = null; using (MemoryStream ResMS = new MemoryStream())
bool IgnoreNullPR = false;
string DbgServiceName = string.Empty;
if (Session is HDomain Dom)
{ {
if (Request.DomCmd == IpcDomCmd.SendMsg) BinaryWriter ResWriter = new BinaryWriter(ResMS);
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
object Obj = Dom.GetObject(Request.DomObjId); ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
if (Obj is HDomain) Session.Service.CallMethod(Context);
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}"; Response.RawData = ResMS.ToArray();
}
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);
} }
} }
else if (Request.Type == IpcMessageType.Control) else if (Request.Type == IpcMessageType.Control)
@ -128,11 +53,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{ {
case 0: case 0:
{ {
HDomain Dom = new HDomain(Session); Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
Process.HandleTable.ReplaceData(HndId, Dom);
Request = FillResponse(Response, 0, Dom.Add(Dom));
break; break;
} }
@ -198,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{ {
BinaryWriter Writer = new BinaryWriter(MS); BinaryWriter Writer = new BinaryWriter(MS);
Writer.Write(SfcoMagic); Writer.Write(IpcMagic.Sfco);
Writer.Write(Result); Writer.Write(Result);
if (Data != null) if (Data != null)

View file

@ -125,8 +125,7 @@ namespace Ryujinx.Core.OsHle.Ipc
Reader.ReadInt64(); //Padding Reader.ReadInt64(); //Padding
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + Environment.NewLine +
$" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine +
$" DomObjId: {DomObjId.ToString()}" + Environment.NewLine; $" DomObjId: {DomObjId.ToString()}" + Environment.NewLine;
} }

View file

@ -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;
}
}

View file

@ -17,10 +17,6 @@ namespace Ryujinx.Core.OsHle.Ipc
public List<int> ResponseObjIds { get; private set; } public List<int> 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 byte[] RawData { get; set; }
public IpcMessage() public IpcMessage()
@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc
ResponseObjIds = new List<int>(); ResponseObjIds = new List<int>();
} }
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)) using (MemoryStream MS = new MemoryStream(Data))
{ {
BinaryReader Reader = new BinaryReader(MS); 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 Word0 = Reader.ReadInt32();
int Word1 = Reader.ReadInt32(); int Word1 = Reader.ReadInt32();
@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc
RecvListCount = 0; 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); RawData = Reader.ReadBytes(RawDataSize);
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); 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... //This is the weirdest padding I've seen so far...
int Pad1 = 0x10 - Pad0; int Pad1 = 0x10 - Pad0;
DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4; DataLength = (DataLength + Pad0 + Pad1) / 4;
DataLength += ResponseObjIds.Count;
Word1 = DataLength & 0x3ff; Word1 = DataLength & 0x3ff;
@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc
MS.Seek(Pad0, SeekOrigin.Current); MS.Seek(Pad0, SeekOrigin.Current);
if (IsDomain)
{
Writer.Write(ResponseObjIds.Count);
Writer.Write(0);
Writer.Write(0L);
}
if (RawData != null) if (RawData != null)
{ {
Writer.Write(RawData); Writer.Write(RawData);
} }
foreach (int Id in ResponseObjIds)
{
Writer.Write(Id);
}
Writer.Write(new byte[Pad1]); Writer.Write(new byte[Pad1]);
return MS.ToArray(); return MS.ToArray();

View file

@ -6,6 +6,5 @@ namespace Ryujinx.Core.OsHle
public const int InvalidHandle = 114; public const int InvalidHandle = 114;
public const int Timeout = 117; public const int Timeout = 117;
public const int InvalidInfo = 120; public const int InvalidInfo = 120;
public const int InvalidIpcReq = 123;
} }
} }

View file

@ -16,7 +16,7 @@ namespace Ryujinx.Core.OsHle
private object EnterWaitLock; private object EnterWaitLock;
private ConcurrentQueue<HThread> WaitingThreads; private ConcurrentQueue<KThread> WaitingThreads;
public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle) public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
{ {
@ -27,10 +27,10 @@ namespace Ryujinx.Core.OsHle
EnterWaitLock = new object(); EnterWaitLock = new object();
WaitingThreads = new ConcurrentQueue<HThread>(); WaitingThreads = new ConcurrentQueue<KThread>();
} }
public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle) public void WaitForLock(KThread RequestingThread, int RequestingThreadHandle)
{ {
AcquireMutexValue(); AcquireMutexValue();
@ -83,11 +83,11 @@ namespace Ryujinx.Core.OsHle
ReleaseMutexValue(); ReleaseMutexValue();
HThread[] UnlockedThreads = new HThread[WaitingThreads.Count]; KThread[] UnlockedThreads = new KThread[WaitingThreads.Count];
int Index = 0; int Index = 0;
while (WaitingThreads.TryDequeue(out HThread Thread)) while (WaitingThreads.TryDequeue(out KThread Thread))
{ {
UnlockedThreads[Index++] = Thread; UnlockedThreads[Index++] = Thread;
} }

View file

@ -5,6 +5,7 @@ using Ryujinx.Core.Loaders;
using Ryujinx.Core.Loaders.Executables; using Ryujinx.Core.Loaders.Executables;
using Ryujinx.Core.OsHle.Exceptions; using Ryujinx.Core.OsHle.Exceptions;
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices.NvServices;
using Ryujinx.Core.OsHle.Svc; using Ryujinx.Core.OsHle.Svc;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -31,21 +32,21 @@ namespace Ryujinx.Core.OsHle
public AMemory Memory { get; private set; } public AMemory Memory { get; private set; }
public ServiceMgr Services { get; private set; }
public KProcessScheduler Scheduler { get; private set; } public KProcessScheduler Scheduler { get; private set; }
public KProcessHandleTable HandleTable { get; private set; } public KProcessHandleTable HandleTable { get; private set; }
public AppletStateMgr AppletState { get; private set; }
private SvcHandler SvcHandler; private SvcHandler SvcHandler;
private ConcurrentDictionary<int, AThread> TlsSlots; private ConcurrentDictionary<int, AThread> TlsSlots;
private ConcurrentDictionary<long, HThread> ThreadsByTpidr; private ConcurrentDictionary<long, KThread> ThreadsByTpidr;
private List<Executable> Executables; private List<Executable> Executables;
private HThread MainThread; private KThread MainThread;
private long ImageBase; private long ImageBase;
@ -60,17 +61,17 @@ namespace Ryujinx.Core.OsHle
Memory = new AMemory(); Memory = new AMemory();
Services = new ServiceMgr();
HandleTable = new KProcessHandleTable(); HandleTable = new KProcessHandleTable();
Scheduler = new KProcessScheduler(); Scheduler = new KProcessScheduler();
AppletState = new AppletStateMgr();
SvcHandler = new SvcHandler(Ns, this); SvcHandler = new SvcHandler(Ns, this);
TlsSlots = new ConcurrentDictionary<int, AThread>(); TlsSlots = new ConcurrentDictionary<int, AThread>();
ThreadsByTpidr = new ConcurrentDictionary<long, HThread>(); ThreadsByTpidr = new ConcurrentDictionary<long, KThread>();
Executables = new List<Executable>(); Executables = new List<Executable>();
@ -132,7 +133,7 @@ namespace Ryujinx.Core.OsHle
return false; return false;
} }
MainThread = HandleTable.GetData<HThread>(Handle); MainThread = HandleTable.GetData<KThread>(Handle);
if (NeedsHbAbi) if (NeedsHbAbi)
{ {
@ -186,7 +187,7 @@ namespace Ryujinx.Core.OsHle
AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint); 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); int Handle = HandleTable.OpenHandle(ThreadHnd);
@ -311,9 +312,9 @@ namespace Ryujinx.Core.OsHle
return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize); 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!"); Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!");
} }
@ -344,11 +345,27 @@ namespace Ryujinx.Core.OsHle
} }
Disposed = true; Disposed = true;
Services.Dispose(); foreach (object Obj in HandleTable.Clear())
HandleTable.Dispose(); {
if (Obj is KSession Session)
{
Session.Dispose();
}
}
ServiceNvDrv.Fds.DeleteProcess(this);
ServiceNvDrv.NvMaps.DeleteProcess(this);
ServiceNvDrv.NvMapsById.DeleteProcess(this);
Scheduler.Dispose(); Scheduler.Dispose();
AppletState.Dispose();
SvcHandler.Dispose(); SvcHandler.Dispose();
Memory.Dispose(); Memory.Dispose();
Logging.Info($"Process {ProcessId} exiting..."); Logging.Info($"Process {ProcessId} exiting...");

View file

@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle
public Switch Ns { get; private set; } public Switch Ns { get; private set; }
public Process Process { get; private set; } public Process Process { get; private set; }
public AMemory Memory { 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 Request { get; private set; }
public IpcMessage Response { get; private set; } public IpcMessage Response { get; private set; }
public BinaryReader RequestData { get; private set; } public BinaryReader RequestData { get; private set; }
@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle
Switch Ns, Switch Ns,
Process Process, Process Process,
AMemory Memory, AMemory Memory,
HSession Session, KSession Session,
IpcMessage Request, IpcMessage Request,
IpcMessage Response, IpcMessage Response,
BinaryReader RequestData, BinaryReader RequestData,

View file

@ -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<string, IIpcService> Services;
public ServiceMgr()
{
Services = new Dictionary<string, IIpcService>();
}
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();
}
}
}
}
}

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Acc namespace Ryujinx.Core.OsHle.IpcServices.Acc
{ {
class IManagerForApplication : IIpcService class IManagerForApplication : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IManagerForApplication() public IManagerForApplication()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Acc namespace Ryujinx.Core.OsHle.IpcServices.Acc
{ {
class IProfile : IIpcService class IProfile : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IProfile() public IProfile()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Acc namespace Ryujinx.Core.OsHle.IpcServices.Acc
{ {
class ServiceAcc : IIpcService class ServiceAcc : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAcc() public ServiceAcc()
{ {

View file

@ -0,0 +1,7 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
static class AmErr
{
public const int NoMessages = 3;
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
enum FocusState
{
InFocus = 1,
OutOfFocus = 2
}
}

View file

@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IApplicationFunctions : IIpcService class IApplicationFunctions : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IApplicationFunctions() public IApplicationFunctions()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IApplicationProxy : IIpcService class IApplicationProxy : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IApplicationProxy() public IApplicationProxy()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IAudioController : IIpcService class IAudioController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioController() public IAudioController()
{ {

View file

@ -1,13 +1,16 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.ErrorCode;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ICommonStateGetter : IIpcService class ICommonStateGetter : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ICommonStateGetter() public ICommonStateGetter()
{ {
@ -17,37 +20,31 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
{ 1, ReceiveMessage }, { 1, ReceiveMessage },
{ 5, GetOperationMode }, { 5, GetOperationMode },
{ 6, GetPerformanceMode }, { 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) 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; return 0;
} }
public long ReceiveMessage(ServiceCtx Context) public long ReceiveMessage(ServiceCtx Context)
{ {
//Program expects 0xF at 0x17ae70 on puyo sdk, if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message))
//otherwise runs on a infinite loop until it reads said value. {
//What it means is still unknown. return MakeError(ErrorModule.Am, AmErr.NoMessages);
Context.ResponseData.Write(0xfL); }
return 0; //0x680; Context.ResponseData.Write((int)Message);
return 0;
} }
public long GetOperationMode(ServiceCtx Context) public long GetOperationMode(ServiceCtx Context)
@ -66,7 +63,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
public long GetCurrentFocusState(ServiceCtx Context) public long GetCurrentFocusState(ServiceCtx Context)
{ {
Context.ResponseData.Write((byte)FocusState.InFocus); Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState);
return 0; return 0;
} }

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IDebugFunctions : IIpcService class IDebugFunctions : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IDebugFunctions() public IDebugFunctions()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IDisplayController : IIpcService class IDisplayController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IDisplayController() public IDisplayController()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ILibraryAppletCreator : IIpcService class ILibraryAppletCreator : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ILibraryAppletCreator() public ILibraryAppletCreator()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ISelfController : IIpcService class ISelfController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISelfController() public ISelfController()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IStorage : IIpcService class IStorage : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public byte[] Data { get; private set; } public byte[] Data { get; private set; }

View file

@ -5,11 +5,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IStorageAccessor : IIpcService class IStorageAccessor : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IStorage Storage; private IStorage Storage;

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IWindowController : IIpcService class IWindowController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IWindowController() public IWindowController()
{ {

View file

@ -0,0 +1,9 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
enum MessageInfo
{
FocusStateChanged = 0xf,
OperationModeChanged = 0x1e,
PerformanceModeChanged = 0x1f
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
enum OperationMode
{
Handheld = 0,
Docked = 1
}
}

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ServiceAppletOE : IIpcService class ServiceAppletOE : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAppletOE() public ServiceAppletOE()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Apm namespace Ryujinx.Core.OsHle.IpcServices.Apm
{ {
class ISession : IIpcService class ISession : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISession() public ISession()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Apm namespace Ryujinx.Core.OsHle.IpcServices.Apm
{ {
class ServiceApm : IIpcService class ServiceApm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceApm() public ServiceApm()
{ {

View file

@ -5,11 +5,11 @@ using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class IAudioDevice : IIpcService class IAudioDevice : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioDevice() public IAudioDevice()
{ {

View file

@ -7,17 +7,19 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class IAudioOut : IIpcService, IDisposable class IAudioOut : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IAalOutput AudioOut; private IAalOutput AudioOut;
private KEvent ReleaseEvent;
private int Track; private int Track;
public IAudioOut(IAalOutput AudioOut, int Track) public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
{ {
m_Commands = new Dictionary<int, ServiceProcessRequest>() m_Commands = new Dictionary<int, ServiceProcessRequest>()
{ {
@ -32,8 +34,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ 8, GetReleasedAudioOutBufferEx } { 8, GetReleasedAudioOutBufferEx }
}; };
this.AudioOut = AudioOut; this.AudioOut = AudioOut;
this.Track = Track; this.ReleaseEvent = ReleaseEvent;
this.Track = Track;
} }
public long GetAudioOutState(ServiceCtx Context) public long GetAudioOutState(ServiceCtx Context)
@ -77,7 +80,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long RegisterBufferEvent(ServiceCtx Context) 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); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
@ -143,6 +146,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
if (Disposing) if (Disposing)
{ {
AudioOut.CloseTrack(Track); AudioOut.CloseTrack(Track);
ReleaseEvent.Dispose();
} }
} }
} }

View file

@ -1,14 +1,17 @@
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class IAudioRenderer : IIpcService class IAudioRenderer : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent UpdateEvent;
public IAudioRenderer() public IAudioRenderer()
{ {
@ -19,6 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ 6, StopAudioRenderer }, { 6, StopAudioRenderer },
{ 7, QuerySystemEvent } { 7, QuerySystemEvent }
}; };
UpdateEvent = new KEvent();
} }
public long RequestUpdateAudioRenderer(ServiceCtx Context) public long RequestUpdateAudioRenderer(ServiceCtx Context)
@ -41,6 +46,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
Context.Memory.WriteInt32(Position + Offset, 5); Context.Memory.WriteInt32(Position + Offset, 5);
} }
//TODO: We shouldn't be signaling this here.
UpdateEvent.Handle.Set();
return 0; return 0;
} }
@ -56,11 +64,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long QuerySystemEvent(ServiceCtx Context) 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); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0; return 0;
} }
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
UpdateEvent.Dispose();
}
}
} }
} }

View file

@ -1,18 +1,17 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Audio; using Ryujinx.Audio;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class ServiceAudOut : IIpcService class ServiceAudOut : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudOut() public ServiceAudOut()
{ {
@ -73,9 +72,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
Channels = 2; 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(SampleRate);
Context.ResponseData.Write(Channels); Context.ResponseData.Write(Channels);

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class ServiceAudRen : IIpcService class ServiceAudRen : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudRen() public ServiceAudRen()
{ {

View file

@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
public Socket Handle; public Socket Handle;
} }
class ServiceBsd : IIpcService class ServiceBsd : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private List<SocketBsd> Sockets = new List<SocketBsd>(); private List<SocketBsd> Sockets = new List<SocketBsd>();

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Friend namespace Ryujinx.Core.OsHle.IpcServices.Friend
{ {
class IFriendService : IIpcService class IFriendService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IFriendService() public IFriendService()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Friend namespace Ryujinx.Core.OsHle.IpcServices.Friend
{ {
class ServiceFriend : IIpcService class ServiceFriend : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceFriend() public ServiceFriend()
{ {

View file

@ -7,13 +7,13 @@ using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IDirectory : IIpcService, IDisposable class IDirectory : IpcService, IDisposable
{ {
private const int DirectoryEntrySize = 0x310; private const int DirectoryEntrySize = 0x310;
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private List<string> DirectoryEntries; private List<string> DirectoryEntries;

View file

@ -6,11 +6,11 @@ using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IFile : IIpcService, IDisposable class IFile : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Stream BaseStream; private Stream BaseStream;

View file

@ -5,15 +5,14 @@ using System.IO;
using System.Text; using System.Text;
using static Ryujinx.Core.OsHle.ErrorCode; using static Ryujinx.Core.OsHle.ErrorCode;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IFileSystem : IIpcService class IFileSystem : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private HashSet<string> OpenPaths; private HashSet<string> OpenPaths;

View file

@ -5,11 +5,11 @@ using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IStorage : IIpcService class IStorage : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Stream BaseStream; private Stream BaseStream;

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class ServiceFspSrv : IIpcService class ServiceFspSrv : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceFspSrv() public ServiceFspSrv()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Hid namespace Ryujinx.Core.OsHle.IpcServices.Hid
{ {
class IActiveApplicationDeviceList : IIpcService class IActiveApplicationDeviceList : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IActiveApplicationDeviceList() public IActiveApplicationDeviceList()
{ {

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Hid namespace Ryujinx.Core.OsHle.IpcServices.Hid
{ {
class IAppletResource : IIpcService class IAppletResource : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private HSharedMem HidSharedMem; private HSharedMem HidSharedMem;

View file

@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using Ryujinx.Core.Input; using Ryujinx.Core.Input;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Hid namespace Ryujinx.Core.OsHle.IpcServices.Hid
{ {
class ServiceHid : IIpcService class ServiceHid : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceHid() public ServiceHid()
{ {

View file

@ -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<int, ServiceProcessRequest> 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<IIpcService>(Id);
}
}
}

View file

@ -7,11 +7,11 @@ using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.Lm namespace Ryujinx.Core.OsHle.IpcServices.Lm
{ {
class ILogger : IIpcService class ILogger : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ILogger() public ILogger()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Lm namespace Ryujinx.Core.OsHle.IpcServices.Lm
{ {
class ServiceLm : IIpcService class ServiceLm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceLm() public ServiceLm()
{ {
@ -21,8 +19,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
public long Initialize(ServiceCtx Context) public long Initialize(ServiceCtx Context)
{ {
Context.Session.Initialize();
MakeObject(Context, new ILogger()); MakeObject(Context, new ILogger());
return 0; return 0;

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ {
class IGeneralService : IIpcService class IGeneralService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IGeneralService() public IGeneralService()
{ {

View file

@ -1,13 +1,17 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ {
class IRequest : IIpcService class IRequest : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent Event;
public IRequest() public IRequest()
{ {
@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ 1, GetResult }, { 1, GetResult },
{ 2, GetSystemEventReadableHandles } { 2, GetSystemEventReadableHandles }
}; };
Event = new KEvent();
} }
// -> i32
public long GetRequestState(ServiceCtx Context) public long GetRequestState(ServiceCtx Context)
{ {
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
//GetSystemEventReadableHandles() -> (KObject, KObject) //GetSystemEventReadableHandles() -> (KObject, KObject)
public long GetSystemEventReadableHandles(ServiceCtx Context) 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; return 0;
} }
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
}
} }
} }

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ {
class ServiceNifm : IIpcService class ServiceNifm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceNifm() public ServiceNifm()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Ns namespace Ryujinx.Core.OsHle.IpcServices.Ns
{ {
class ServiceNs : IIpcService class ServiceNs : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceNs() public ServiceNs()
{ {

View file

@ -1,4 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.Utilities; using Ryujinx.Core.OsHle.Utilities;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
@ -7,20 +8,22 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.NvServices namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ {
class ServiceNvDrv : IIpcService class ServiceNvDrv : IpcService, IDisposable
{ {
private delegate long ServiceProcessIoctl(ServiceCtx Context); private delegate long ServiceProcessIoctl(ServiceCtx Context);
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds; private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
private IdDictionary Fds; public static GlobalStateTable Fds { get; private set; }
private IdDictionary NvMaps; public static GlobalStateTable NvMaps { get; private set; }
private IdDictionary NvMapsById; public static GlobalStateTable NvMapsById { get; private set; }
private KEvent Event;
public ServiceNvDrv() public ServiceNvDrv()
{ {
@ -64,10 +67,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ ("/dev/nvmap", 0x010e), NvMapIocGetId }, { ("/dev/nvmap", 0x010e), NvMapIocGetId },
}; };
Fds = new IdDictionary(); Event = new KEvent();
}
NvMaps = new IdDictionary(); static ServiceNvDrv()
NvMapsById = new IdDictionary(); {
Fds = new GlobalStateTable();
NvMaps = new GlobalStateTable();
NvMapsById = new GlobalStateTable();
} }
public long Open(ServiceCtx Context) public long Open(ServiceCtx Context)
@ -76,7 +84,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); 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(Fd);
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -89,7 +97,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Fd = Context.RequestData.ReadInt32(); int Fd = Context.RequestData.ReadInt32();
int Cmd = Context.RequestData.ReadInt32() & 0xffff; int Cmd = Context.RequestData.ReadInt32() & 0xffff;
NvFd FdData = Fds.GetData<NvFd>(Fd); NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
long Position = Context.Request.GetSendBuffPtr(); long Position = Context.Request.GetSendBuffPtr();
@ -109,7 +117,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ {
int Fd = Context.RequestData.ReadInt32(); int Fd = Context.RequestData.ReadInt32();
Fds.Delete(Fd); Fds.Delete(Context.Process, Fd);
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -131,7 +139,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Fd = Context.RequestData.ReadInt32(); int Fd = Context.RequestData.ReadInt32();
int EventId = 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); Context.ResponseData.Write(0);
@ -203,7 +214,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0; return 0;
} }
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -550,9 +561,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
NvMap Map = new NvMap() { Size = Size }; 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); Context.Memory.WriteInt32(Position + 4, Map.Handle);
@ -567,7 +578,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Id = Context.Memory.ReadInt32(Position); int Id = Context.Memory.ReadInt32(Position);
NvMap Map = NvMapsById.GetData<NvMap>(Id); NvMap Map = NvMapsById.GetData<NvMap>(Context.Process, Id);
if (Map == null) if (Map == null)
{ {
@ -594,7 +605,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
byte Kind = (byte)Reader.ReadInt64(); byte Kind = (byte)Reader.ReadInt64();
long Addr = Reader.ReadInt64(); long Addr = Reader.ReadInt64();
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -620,7 +631,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32(); int Handle = Reader.ReadInt32();
int Padding = Reader.ReadInt32(); int Padding = Reader.ReadInt32();
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -645,7 +656,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32(); int Handle = Reader.ReadInt32();
int Param = Reader.ReadInt32(); int Param = Reader.ReadInt32();
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -675,7 +686,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Context.Memory.ReadInt32(Position + 4); int Handle = Context.Memory.ReadInt32(Position + 4);
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -689,9 +700,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0; return 0;
} }
public NvMap GetNvMap(int Handle) public void Dispose()
{ {
return NvMaps.GetData<NvMap>(Handle); Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
} }
} }
} }

View file

@ -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);
}
}
}
}

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Pctl namespace Ryujinx.Core.OsHle.IpcServices.Pctl
{ {
class IParentalControlService : IIpcService class IParentalControlService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IParentalControlService() public IParentalControlService()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Pctl namespace Ryujinx.Core.OsHle.IpcServices.Pctl
{ {
class ServicePctl : IIpcService class ServicePctl : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServicePctl() public ServicePctl()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Pl namespace Ryujinx.Core.OsHle.IpcServices.Pl
{ {
class ServicePl : IIpcService class ServicePl : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServicePl() public ServicePl()
{ {

View file

@ -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);
}
}
}

View file

@ -5,11 +5,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Set namespace Ryujinx.Core.OsHle.IpcServices.Set
{ {
class ServiceSet : IIpcService class ServiceSet : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSet() public ServiceSet()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Set namespace Ryujinx.Core.OsHle.IpcServices.Set
{ {
class ServiceSetSys : IIpcService class ServiceSetSys : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSetSys() public ServiceSetSys()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres
{ {
class ServiceSfdnsres : IIpcService class ServiceSfdnsres : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSfdnsres() public ServiceSfdnsres()
{ {

View file

@ -4,11 +4,13 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Sm namespace Ryujinx.Core.OsHle.IpcServices.Sm
{ {
class ServiceSm : IIpcService class ServiceSm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private bool IsInitialized;
public ServiceSm() public ServiceSm()
{ {
@ -23,7 +25,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
public long Initialize(ServiceCtx Context) public long Initialize(ServiceCtx Context)
{ {
Context.Session.Initialize(); IsInitialized = true;
return 0; return 0;
} }
@ -31,7 +33,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
public long GetService(ServiceCtx Context) public long GetService(ServiceCtx Context)
{ {
//Only for kernel version > 3.0.0. //Only for kernel version > 3.0.0.
if (!Context.Session.IsInitialized) if (!IsInitialized)
{ {
//return SmNotInitialized; //return SmNotInitialized;
} }
@ -55,7 +57,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
return 0; 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); int Handle = Context.Process.HandleTable.OpenHandle(Session);

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Ssl namespace Ryujinx.Core.OsHle.IpcServices.Ssl
{ {
class ServiceSsl : IIpcService class ServiceSsl : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSsl() public ServiceSsl()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ISteadyClock : IIpcService class ISteadyClock : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISteadyClock() public ISteadyClock()
{ {

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ISystemClock : IIpcService class ISystemClock : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ITimeZoneService : IIpcService class ITimeZoneService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ServiceTime : IIpcService class ServiceTime : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceTime() public ServiceTime()
{ {

View file

@ -1,19 +1,17 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class IApplicationDisplayService : IIpcService class IApplicationDisplayService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IdDictionary Displays; private IdDictionary Displays;
@ -145,7 +143,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
string Name = GetDisplayName(Context); 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); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);

View file

@ -1,4 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.IpcServices.Android; using Ryujinx.Core.OsHle.IpcServices.Android;
using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Gal;
@ -7,11 +8,13 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class IHOSBinderDriver : IIpcService, IDisposable class IHOSBinderDriver : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent ReleaseEvent;
private NvFlinger Flinger; private NvFlinger Flinger;
@ -24,7 +27,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ 2, GetNativeHandle } { 2, GetNativeHandle }
}; };
Flinger = new NvFlinger(Renderer); ReleaseEvent = new KEvent();
Flinger = new NvFlinger(Renderer, ReleaseEvent);
} }
public long TransactParcel(ServiceCtx Context) public long TransactParcel(ServiceCtx Context)
@ -56,7 +61,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
int Id = Context.RequestData.ReadInt32(); int Id = Context.RequestData.ReadInt32();
uint Unk = Context.RequestData.ReadUInt32(); 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; return 0;
} }
@ -70,6 +77,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
if (Disposing) if (Disposing)
{ {
ReleaseEvent.Dispose();
Flinger.Dispose(); Flinger.Dispose();
} }
} }

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class IManagerDisplayService : IIpcService class IManagerDisplayService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IManagerDisplayService() public IManagerDisplayService()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class ISystemDisplayService : IIpcService class ISystemDisplayService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISystemDisplayService() public ISystemDisplayService()
{ {

View file

@ -1,4 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices.NvServices; using Ryujinx.Core.OsHle.IpcServices.NvServices;
using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Gal;
using System; using System;
@ -17,6 +18,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
private Dictionary<(string, int), ServiceProcessParcel> Commands; private Dictionary<(string, int), ServiceProcessParcel> Commands;
private KEvent ReleaseEvent;
private IGalRenderer Renderer;
private const int BufferQueueCount = 0x40; private const int BufferQueueCount = 0x40;
private const int BufferQueueMask = BufferQueueCount - 1; private const int BufferQueueMask = BufferQueueCount - 1;
@ -55,8 +60,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
public GbpBuffer Data; public GbpBuffer Data;
} }
private IGalRenderer Renderer;
private BufferEntry[] BufferQueue; private BufferEntry[] BufferQueue;
private ManualResetEvent WaitBufferFree; private ManualResetEvent WaitBufferFree;
@ -69,7 +72,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
private bool KeepRunning; private bool KeepRunning;
public NvFlinger(IGalRenderer Renderer) public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent)
{ {
Commands = new Dictionary<(string, int), ServiceProcessParcel>() Commands = new Dictionary<(string, int), ServiceProcessParcel>()
{ {
@ -83,8 +86,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
{ ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect }, { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect },
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer } { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
}; };
this.Renderer = Renderer; this.Renderer = Renderer;
this.ReleaseEvent = ReleaseEvent;
BufferQueue = new BufferEntry[0x40]; BufferQueue = new BufferEntry[0x40];
@ -293,6 +297,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
BufferQueue[Slot].State = BufferState.Free; BufferQueue[Slot].State = BufferState.Free;
ReleaseEvent.Handle.Set();
WaitBufferFree.Set(); WaitBufferFree.Set();
return; return;
@ -377,6 +383,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
Interlocked.Decrement(ref RenderQueueCount); Interlocked.Decrement(ref RenderQueueCount);
ReleaseEvent.Handle.Set();
lock (WaitBufferFree) lock (WaitBufferFree)
{ {
WaitBufferFree.Set(); WaitBufferFree.Set();
@ -397,9 +405,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
NvMapHandle = BitConverter.ToInt32(RawValue, 0); NvMapHandle = BitConverter.ToInt32(RawValue, 0);
} }
ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv"); return ServiceNvDrv.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
return NvDrv.GetNvMap(NvMapHandle);
} }
private int GetFreeSlotBlocking(int Width, int Height) private int GetFreeSlotBlocking(int Width, int Height)

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class ServiceVi : IIpcService class ServiceVi : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceVi() public ServiceVi()
{ {

View file

@ -3,6 +3,7 @@ using ChocolArm64.State;
using Ryujinx.Core.OsHle.Exceptions; using Ryujinx.Core.OsHle.Exceptions;
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.IpcServices;
using System; using System;
using System.Threading; using System.Threading;
@ -34,7 +35,28 @@ namespace Ryujinx.Core.OsHle.Svc
{ {
int Handle = (int)ThreadState.X0; 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; ThreadState.X0 = 0;
} }
@ -43,25 +65,78 @@ namespace Ryujinx.Core.OsHle.Svc
{ {
int Handle = (int)ThreadState.X0; int Handle = (int)ThreadState.X0;
//TODO: Implement events. KEvent Event = Process.HandleTable.GetData<KEvent>(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) private void SvcWaitSynchronization(AThreadState ThreadState)
{ {
long HandlesPtr = (long)ThreadState.X0; long HandlesPtr = (long)ThreadState.X1;
int HandlesCount = (int)ThreadState.X2; int HandlesCount = (int)ThreadState.X2;
long Timeout = (long)ThreadState.X3; 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<KSynchronizationObject>(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); 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); Process.Scheduler.Resume(CurrThread);
ThreadState.X0 = 0; ThreadState.X0 = Result;
if (Result == 0)
{
ThreadState.X1 = (ulong)HandleIndex;
}
} }
private void SvcGetSystemTick(AThreadState ThreadState) 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 //TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise. //actually exists, return error codes otherwise.
KSession Session = new KSession(ServiceFactory.MakeService(Name));
HSession Session = new HSession(Process.Services.GetService(Name));
ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
@ -89,65 +163,46 @@ namespace Ryujinx.Core.OsHle.Svc
private void SvcSendSyncRequest(AThreadState ThreadState) private void SvcSendSyncRequest(AThreadState ThreadState)
{ {
SendSyncRequest(ThreadState, false); SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
} }
private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState) 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; KThread CurrThread = Process.GetThread(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);
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
HSession Session = Process.HandleTable.GetData<HSession>(Handle); KSession Session = Process.HandleTable.GetData<KSession>(Handle);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
if (Session != null) if (Session != null)
{ {
IpcHandler.IpcCall( Process.Scheduler.Suspend(CurrThread.ProcessorId);
Ns,
Process,
Memory,
Session,
Cmd,
ThreadState.ThreadId,
CmdPtr,
Handle);
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; ThreadState.X0 = 0;
} }
else 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) private void SvcBreak(AThreadState ThreadState)

View file

@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc
{ {
int Handle = (int)ThreadState.X0; int Handle = (int)ThreadState.X0;
HThread Thread = Process.HandleTable.GetData<HThread>(Handle); KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
if (Thread != null) if (Thread != null)
{ {
@ -53,16 +53,18 @@ namespace Ryujinx.Core.OsHle.Svc
private void SvcExitThread(AThreadState ThreadState) private void SvcExitThread(AThreadState ThreadState)
{ {
HThread CurrThread = Process.GetThread(ThreadState.Tpidr); KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
CurrThread.Thread.StopExecution(); CurrThread.Thread.StopExecution();
CurrThread.Handle.Set();
} }
private void SvcSleepThread(AThreadState ThreadState) private void SvcSleepThread(AThreadState ThreadState)
{ {
ulong NanoSecs = ThreadState.X0; ulong NanoSecs = ThreadState.X0;
HThread CurrThread = Process.GetThread(ThreadState.Tpidr); KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
if (NanoSecs == 0) if (NanoSecs == 0)
{ {
@ -78,7 +80,7 @@ namespace Ryujinx.Core.OsHle.Svc
{ {
int Handle = (int)ThreadState.X1; int Handle = (int)ThreadState.X1;
HThread Thread = Process.HandleTable.GetData<HThread>(Handle); KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
if (Thread != null) if (Thread != null)
{ {
@ -91,10 +93,10 @@ namespace Ryujinx.Core.OsHle.Svc
private void SvcSetThreadPriority(AThreadState ThreadState) private void SvcSetThreadPriority(AThreadState ThreadState)
{ {
int Prio = (int)ThreadState.X0;
int Handle = (int)ThreadState.X1; int Handle = (int)ThreadState.X1;
int Prio = (int)ThreadState.X0;
HThread Thread = Process.HandleTable.GetData<HThread>(Handle); KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
if (Thread != null) if (Thread != null)
{ {
@ -117,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Svc
{ {
int Handle = (int)ThreadState.X0; int Handle = (int)ThreadState.X0;
HThread Thread = Process.HandleTable.GetData<HThread>(Handle); KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
if (Thread != null) if (Thread != null)
{ {

View file

@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc
long MutexAddress = (long)ThreadState.X1; long MutexAddress = (long)ThreadState.X1;
int RequestingThreadHandle = (int)ThreadState.X2; int RequestingThreadHandle = (int)ThreadState.X2;
HThread RequestingThread = Process.HandleTable.GetData<HThread>(RequestingThreadHandle); KThread RequestingThread = Process.HandleTable.GetData<KThread>(RequestingThreadHandle);
Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle); Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc
int ThreadHandle = (int)ThreadState.X2; int ThreadHandle = (int)ThreadState.X2;
long Timeout = (long)ThreadState.X3; long Timeout = (long)ThreadState.X3;
HThread Thread = Process.HandleTable.GetData<HThread>(ThreadHandle); KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
Mutex M = new Mutex(Process, MutexAddress, ThreadHandle); Mutex M = new Mutex(Process, MutexAddress, ThreadHandle);
@ -72,7 +72,7 @@ namespace Ryujinx.Core.OsHle.Svc
long CondVarAddress = (long)ThreadState.X0; long CondVarAddress = (long)ThreadState.X0;
int Count = (int)ThreadState.X1; 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)) if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv))
{ {

View file

@ -14,10 +14,10 @@ namespace Ryujinx.Core
internal NsGpu Gpu { get; private set; } internal NsGpu Gpu { get; private set; }
internal Horizon Os { get; private set; }
internal VirtualFileSystem VFs { get; private set; } internal VirtualFileSystem VFs { get; private set; }
public Horizon Os { get; private set; }
public SystemSettings Settings { get; private set; } public SystemSettings Settings { get; private set; }
public PerformanceStatistics Statistics { get; private set; } public PerformanceStatistics Statistics { get; private set; }
@ -40,12 +40,12 @@ namespace Ryujinx.Core
this.AudioOut = AudioOut; this.AudioOut = AudioOut;
Gpu = new NsGpu(Renderer); Gpu = new NsGpu(Renderer);
Os = new Horizon(this);
VFs = new VirtualFileSystem(); VFs = new VirtualFileSystem();
Os = new Horizon(this);
Settings = new SystemSettings(); Settings = new SystemSettings();
Statistics = new PerformanceStatistics(); Statistics = new PerformanceStatistics();

View file

@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
private NsGpu Gpu; private NsGpu Gpu;
private int[] Registers; private uint[] Registers;
public NsGpuEngine[] SubChannels; public NsGpuEngine[] SubChannels;
@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
this.Gpu = Gpu; this.Gpu = Gpu;
Registers = new int[0x1000]; Registers = new uint[0x1000];
SubChannels = new NsGpuEngine[8]; SubChannels = new NsGpuEngine[8];
@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
if (Entry.Arguments.Count == 1) if (Entry.Arguments.Count == 1)
{ {
SetRegister(Entry.Register, Entry.Arguments[0]); SetRegister(Entry.Register, (uint)Entry.Arguments[0]);
} }
switch (Entry.Register) switch (Entry.Register)
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu
case NsGpuRegister._3dVertexArray0Fetch: case NsGpuRegister._3dVertexArray0Fetch:
SendVertexBuffers(Memory); SendVertexBuffers(Memory);
break; break;
case NsGpuRegister._3dCbData0: case NsGpuRegister._3dCbData0:
if (GetRegister(NsGpuRegister._3dCbPos) == 0x20) if (GetRegister(NsGpuRegister._3dCbPos) == 0x20)
{ {
@ -62,6 +62,22 @@ namespace Ryujinx.Graphics.Gpu
case NsGpuRegister._3dQueryGet: case NsGpuRegister._3dQueryGet:
HasQuery = true; HasQuery = true;
break; 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._3dQueryAddressHigh) << 32 |
(long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0; (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0;
int Seq = GetRegister(NsGpuRegister._3dQuerySequence); uint Seq = GetRegister(NsGpuRegister._3dQuerySequence);
int Get = GetRegister(NsGpuRegister._3dQueryGet); uint Get = GetRegister(NsGpuRegister._3dQueryGet);
int Mode = Get & 3; uint Mode = Get & 3;
if (Mode == 0) if (Mode == 0)
{ {
@ -85,7 +101,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
Gpu.Renderer.QueueAction(delegate() 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); byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, Size);
int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff; int Stride = (int)GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff;
List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>(); List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>();
for (int Attr = 0; Attr < 16; Attr++) 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, GalVertexAttrib Attrib = new GalVertexAttrib(Attr,
(Packed >> 0) & 0x1f, (Packed >> 0) & 0x1f,
@ -154,10 +170,10 @@ namespace Ryujinx.Graphics.Gpu
long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 | long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 |
(long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0; (long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0;
int CbData = GetRegister(NsGpuRegister._3dCbData0); uint CbData = GetRegister(NsGpuRegister._3dCbData0);
int TicIndex = (CbData >> 0) & 0xfffff; uint TicIndex = (CbData >> 0) & 0xfffff;
int TscIndex = (CbData >> 20) & 0xfff; //I guess? uint TscIndex = (CbData >> 20) & 0xfff; //I guess?
TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20); 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( private static byte[] GetDecodedTexture(
AMemory Memory, AMemory Memory,
NsGpuTextureFormat Format, NsGpuTextureFormat Format,
@ -263,12 +292,12 @@ namespace Ryujinx.Graphics.Gpu
return Data; return Data;
} }
public int GetRegister(NsGpuRegister Register) public uint GetRegister(NsGpuRegister Register)
{ {
return Registers[((int)Register >> 2) & 0xfff]; 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; Registers[((int)Register >> 2) & 0xfff] = Value;
} }

View file

@ -89,5 +89,6 @@ namespace Ryujinx.Graphics.Gpu
_3dCbData13 = 0x23c4, _3dCbData13 = 0x23c4,
_3dCbData14 = 0x23c8, _3dCbData14 = 0x23c8,
_3dCbData15 = 0x23cc, _3dCbData15 = 0x23cc,
_3dSetShader = 0x3890
} }
} }

Some files were not shown because too many files have changed in this diff Show more