[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
{
int OpenTrack(int SampleRate, int Channels, out AudioFormat Format);
int OpenTrack(
int SampleRate,
int Channels,
ReleaseCallback Callback,
out AudioFormat Format);
void CloseTrack(int Track);

View file

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

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

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

View file

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

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

View file

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

View file

@ -1,11 +1,10 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle
{
class IdDictionary : IEnumerable<object>
class IdDictionary
{
private ConcurrentDictionary<int, object> Objs;
@ -39,18 +38,6 @@ namespace Ryujinx.Core.OsHle
throw new InvalidOperationException();
}
public bool ReplaceData(int Id, object Data)
{
if (Objs.ContainsKey(Id))
{
Objs[Id] = Data;
return true;
}
return false;
}
public object GetData(int Id)
{
if (Objs.TryGetValue(Id, out object Data))
@ -71,31 +58,25 @@ namespace Ryujinx.Core.OsHle
return default(T);
}
public bool Delete(int Id)
public object Delete(int Id)
{
if (Objs.TryRemove(Id, out object Obj))
{
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
FreeIdHint = Id;
return true;
return Obj;
}
return false;
return null;
}
IEnumerator<object> IEnumerable<object>.GetEnumerator()
public ICollection<object> Clear()
{
return Objs.Values.GetEnumerator();
}
ICollection<object> Values = Objs.Values;
IEnumerator IEnumerable.GetEnumerator()
{
return Objs.Values.GetEnumerator();
Objs.Clear();
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 Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices;
using System;
using System.IO;
@ -8,20 +7,15 @@ namespace Ryujinx.Core.OsHle.Ipc
{
static class IpcHandler
{
private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
public static void IpcCall(
Switch Ns,
Process Process,
AMemory Memory,
HSession Session,
KSession Session,
IpcMessage Request,
int ThreadId,
long CmdPtr,
int HndId)
long CmdPtr)
{
IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request);
IpcMessage Response = new IpcMessage();
using (MemoryStream Raw = new MemoryStream(Request.RawData))
{
@ -29,94 +23,25 @@ namespace Ryujinx.Core.OsHle.Ipc
if (Request.Type == IpcMessageType.Request)
{
string ServiceName = Session.Service.GetType().Name;
Response.Type = IpcMessageType.Response;
ServiceProcessRequest ProcReq = null;
bool IgnoreNullPR = false;
string DbgServiceName = string.Empty;
if (Session is HDomain Dom)
using (MemoryStream ResMS = new MemoryStream())
{
if (Request.DomCmd == IpcDomCmd.SendMsg)
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
BinaryWriter ResWriter = new BinaryWriter(ResMS);
object Obj = Dom.GetObject(Request.DomObjId);
ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
if (Obj is HDomain)
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
Session.Service.CallMethod(Context);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else if (Obj != null)
{
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
{
Dom.Delete(Request.DomObjId);
Response = FillResponse(Response, 0);
IgnoreNullPR = true;
}
}
else
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
if (Session is HSessionObj)
{
object Obj = ((HSessionObj)Session).Obj;
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
Logging.Debug($"IpcMessage: {DbgServiceName}");
if (ProcReq != null)
{
using (MemoryStream ResMS = new MemoryStream())
{
BinaryWriter ResWriter = new BinaryWriter(ResMS);
ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
long Result = ProcReq(Context);
Response = FillResponse(Response, Result, ResMS.ToArray());
}
}
else if (!IgnoreNullPR)
{
throw new NotImplementedException(DbgServiceName);
Response.RawData = ResMS.ToArray();
}
}
else if (Request.Type == IpcMessageType.Control)
@ -128,11 +53,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{
case 0:
{
HDomain Dom = new HDomain(Session);
Process.HandleTable.ReplaceData(HndId, Dom);
Request = FillResponse(Response, 0, Dom.Add(Dom));
Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
break;
}
@ -198,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{
BinaryWriter Writer = new BinaryWriter(MS);
Writer.Write(SfcoMagic);
Writer.Write(IpcMagic.Sfco);
Writer.Write(Result);
if (Data != null)

View file

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

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 bool IsDomain { get; private set; }
public IpcDomCmd DomCmd { get; private set; }
public int DomObjId { get; private set; }
public byte[] RawData { get; set; }
public IpcMessage()
@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc
ResponseObjIds = new List<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))
{
BinaryReader Reader = new BinaryReader(MS);
Initialize(Reader, CmdPtr, Domain);
Initialize(Reader, CmdPtr);
}
}
private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain)
private void Initialize(BinaryReader Reader, long CmdPtr)
{
IsDomain = Domain;
int Word0 = Reader.ReadInt32();
int Word1 = Reader.ReadInt32();
@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc
RecvListCount = 0;
}
if (Domain && Type == IpcMessageType.Request)
{
int DomWord0 = Reader.ReadInt32();
DomCmd = (IpcDomCmd)(DomWord0 & 0xff);
RawDataSize = (DomWord0 >> 16) & 0xffff;
DomObjId = Reader.ReadInt32();
Reader.ReadInt64(); //Padding
}
RawData = Reader.ReadBytes(RawDataSize);
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
@ -165,9 +139,7 @@ namespace Ryujinx.Core.OsHle.Ipc
//This is the weirdest padding I've seen so far...
int Pad1 = 0x10 - Pad0;
DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4;
DataLength += ResponseObjIds.Count;
DataLength = (DataLength + Pad0 + Pad1) / 4;
Word1 = DataLength & 0x3ff;
@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc
MS.Seek(Pad0, SeekOrigin.Current);
if (IsDomain)
{
Writer.Write(ResponseObjIds.Count);
Writer.Write(0);
Writer.Write(0L);
}
if (RawData != null)
{
Writer.Write(RawData);
}
foreach (int Id in ResponseObjIds)
{
Writer.Write(Id);
}
Writer.Write(new byte[Pad1]);
return MS.ToArray();

View file

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

View file

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

View file

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

View file

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

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
{
class IManagerForApplication : IIpcService
class IManagerForApplication : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IManagerForApplication()
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
class IStorage : IIpcService
class IStorage : IpcService
{
private Dictionary<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; }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,18 +1,17 @@
using ChocolArm64.Memory;
using Ryujinx.Audio;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using System.Text;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud
{
class ServiceAudOut : IIpcService
class ServiceAudOut : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudOut()
{
@ -73,9 +72,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
Channels = 2;
}
int Track = AudioOut.OpenTrack(SampleRate, Channels, out AudioFormat Format);
KEvent ReleaseEvent = new KEvent();
MakeObject(Context, new IAudioOut(AudioOut, Track));
ReleaseCallback Callback = () =>
{
ReleaseEvent.Handle.Set();
};
int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format);
MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));
Context.ResponseData.Write(SampleRate);
Context.ResponseData.Write(Channels);

View file

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

View file

@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
public Socket Handle;
}
class ServiceBsd : IIpcService
class ServiceBsd : IpcService
{
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>();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,13 +1,17 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{
class IRequest : IIpcService
class IRequest : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent Event;
public IRequest()
{
@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ 1, GetResult },
{ 2, GetSystemEventReadableHandles }
};
Event = new KEvent();
}
// -> i32
public long GetRequestState(ServiceCtx Context)
{
Context.ResponseData.Write(0);
@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
//GetSystemEventReadableHandles() -> (KObject, KObject)
public long GetSystemEventReadableHandles(ServiceCtx Context)
{
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
//FIXME: Is this supposed to return 2 events?
int Handle = Context.Process.HandleTable.OpenHandle(Event);
//Todo: Stub
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
return 0;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time
{
class ISystemClock : IIpcService
class ISystemClock : IpcService
{
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);

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time
{
class ITimeZoneService : IIpcService
class ITimeZoneService : IpcService
{
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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,6 +3,7 @@ using ChocolArm64.State;
using Ryujinx.Core.OsHle.Exceptions;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.IpcServices;
using System;
using System.Threading;
@ -34,7 +35,28 @@ namespace Ryujinx.Core.OsHle.Svc
{
int Handle = (int)ThreadState.X0;
Process.HandleTable.CloseHandle(Handle);
object Obj = Process.HandleTable.CloseHandle(Handle);
if (Obj == null)
{
Logging.Warn($"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (Obj is KSession Session)
{
Session.Dispose();
}
else if (Obj is HTransferMem TMem)
{
TMem.Memory.Manager.Reprotect(
TMem.Position,
TMem.Size,
TMem.Perm);
}
ThreadState.X0 = 0;
}
@ -43,25 +65,78 @@ namespace Ryujinx.Core.OsHle.Svc
{
int Handle = (int)ThreadState.X0;
//TODO: Implement events.
KEvent Event = Process.HandleTable.GetData<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)
{
long HandlesPtr = (long)ThreadState.X0;
long HandlesPtr = (long)ThreadState.X1;
int HandlesCount = (int)ThreadState.X2;
long Timeout = (long)ThreadState.X3;
//TODO: Implement events.
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
WaitHandle[] Handles = new WaitHandle[HandlesCount];
for (int Index = 0; Index < HandlesCount; Index++)
{
int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
KSynchronizationObject SyncObj = Process.HandleTable.GetData<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);
int HandleIndex;
ulong Result = 0;
if (Timeout != -1)
{
HandleIndex = WaitHandle.WaitAny(Handles, (int)(Timeout / 1000000));
if (HandleIndex == WaitHandle.WaitTimeout)
{
Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
}
}
else
{
HandleIndex = WaitHandle.WaitAny(Handles);
}
Process.Scheduler.Resume(CurrThread);
ThreadState.X0 = 0;
ThreadState.X0 = Result;
if (Result == 0)
{
ThreadState.X1 = (ulong)HandleIndex;
}
}
private void SvcGetSystemTick(AThreadState ThreadState)
@ -78,8 +153,7 @@ namespace Ryujinx.Core.OsHle.Svc
//TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise.
HSession Session = new HSession(Process.Services.GetService(Name));
KSession Session = new KSession(ServiceFactory.MakeService(Name));
ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
@ -89,65 +163,46 @@ namespace Ryujinx.Core.OsHle.Svc
private void SvcSendSyncRequest(AThreadState ThreadState)
{
SendSyncRequest(ThreadState, false);
SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
}
private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState)
{
SendSyncRequest(ThreadState, true);
SendSyncRequest(
ThreadState,
(long)ThreadState.X0,
(long)ThreadState.X1,
(int)ThreadState.X2);
}
private void SendSyncRequest(AThreadState ThreadState, bool UserBuffer)
private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle)
{
long CmdPtr = ThreadState.Tpidr;
long Size = 0x100;
int Handle = 0;
if (UserBuffer)
{
CmdPtr = (long)ThreadState.X0;
Size = (long)ThreadState.X1;
Handle = (int)ThreadState.X2;
}
else
{
Handle = (int)ThreadState.X0;
}
HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
Process.Scheduler.Suspend(CurrThread.ProcessorId);
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
HSession Session = Process.HandleTable.GetData<HSession>(Handle);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
KSession Session = Process.HandleTable.GetData<KSession>(Handle);
if (Session != null)
{
IpcHandler.IpcCall(
Ns,
Process,
Memory,
Session,
Cmd,
ThreadState.ThreadId,
CmdPtr,
Handle);
Process.Scheduler.Suspend(CurrThread.ProcessorId);
byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
Thread.Yield();
Process.Scheduler.Resume(CurrThread);
ThreadState.X0 = 0;
}
else
{
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidIpcReq);
Logging.Warn($"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
Thread.Yield();
Process.Scheduler.Resume(CurrThread);
}
private void SvcBreak(AThreadState ThreadState)

View file

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

View file

@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc
long MutexAddress = (long)ThreadState.X1;
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);
@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc
int ThreadHandle = (int)ThreadState.X2;
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);
@ -72,7 +72,7 @@ namespace Ryujinx.Core.OsHle.Svc
long CondVarAddress = (long)ThreadState.X0;
int Count = (int)ThreadState.X1;
HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv))
{

View file

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

View file

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

View file

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

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