diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Services')
7 files changed, 253 insertions, 30 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs index 8c4d1008..9ebb0b99 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs @@ -11,35 +11,50 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib { private IApplet _applet; - private AppletFifo<byte[]> _inData; - private AppletFifo<byte[]> _outData; + private AppletSession _normalSession; + private AppletSession _interactiveSession; private KEvent _stateChangedEvent; + private KEvent _normalOutDataEvent; + private KEvent _interactiveOutDataEvent; public ILibraryAppletAccessor(AppletId appletId, Horizon system) { - _stateChangedEvent = new KEvent(system); + _stateChangedEvent = new KEvent(system); + _normalOutDataEvent = new KEvent(system); + _interactiveOutDataEvent = new KEvent(system); - _applet = AppletManager.Create(appletId, system); - _inData = new AppletFifo<byte[]>(); - _outData = new AppletFifo<byte[]>(); - - _applet.AppletStateChanged += OnAppletStateChanged; + _applet = AppletManager.Create(appletId, system); + + _normalSession = new AppletSession(); + _interactiveSession = new AppletSession(); + + _applet.AppletStateChanged += OnAppletStateChanged; + _normalSession.DataAvailable += OnNormalOutData; + _interactiveSession.DataAvailable += OnInteractiveOutData; Logger.PrintInfo(LogClass.ServiceAm, $"Applet '{appletId}' created."); } private void OnAppletStateChanged(object sender, EventArgs e) { - _stateChangedEvent.ReadableEvent.Signal(); + _stateChangedEvent.WritableEvent.Signal(); + } + + private void OnNormalOutData(object sender, EventArgs e) + { + _normalOutDataEvent.WritableEvent.Signal(); + } + + private void OnInteractiveOutData(object sender, EventArgs e) + { + _interactiveOutDataEvent.WritableEvent.Signal(); } [Command(0)] // GetAppletStateChangedEvent() -> handle<copy> public ResultCode GetAppletStateChangedEvent(ServiceCtx context) { - _stateChangedEvent.ReadableEvent.Signal(); - if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success) { throw new InvalidOperationException("Out of handles!"); @@ -54,7 +69,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib // Start() public ResultCode Start(ServiceCtx context) { - return (ResultCode)_applet.Start(_inData, _outData); + return (ResultCode)_applet.Start(_normalSession.GetConsumer(), + _interactiveSession.GetConsumer()); } [Command(30)] @@ -70,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib { IStorage data = GetObject<IStorage>(context, 0); - _inData.Push(data.Data); + _normalSession.Push(data.Data); return ResultCode.Success; } @@ -79,10 +95,70 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib // PopOutData() -> object<nn::am::service::IStorage> public ResultCode PopOutData(ServiceCtx context) { - byte[] data = _outData.Pop(); + if(_normalSession.TryPop(out byte[] data)) + { + MakeObject(context, new IStorage(data)); + + _normalOutDataEvent.WritableEvent.Clear(); + + return ResultCode.Success; + } + + return ResultCode.NotAvailable; + } + + [Command(103)] + // PushInteractiveInData(object<nn::am::service::IStorage>) + public ResultCode PushInteractiveInData(ServiceCtx context) + { + IStorage data = GetObject<IStorage>(context, 0); + + _interactiveSession.Push(data.Data); + + return ResultCode.Success; + } + + [Command(104)] + // PopInteractiveOutData() -> object<nn::am::service::IStorage> + public ResultCode PopInteractiveOutData(ServiceCtx context) + { + if(_interactiveSession.TryPop(out byte[] data)) + { + MakeObject(context, new IStorage(data)); + + _interactiveOutDataEvent.WritableEvent.Clear(); + + return ResultCode.Success; + } + + return ResultCode.NotAvailable; + } + + [Command(105)] + // GetPopOutDataEvent() -> handle<copy> + public ResultCode GetPopOutDataEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return ResultCode.Success; + } + + [Command(106)] + // GetPopInteractiveOutDataEvent() -> handle<copy> + public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context) + { + if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - MakeObject(context, new IStorage(data)); - return ResultCode.Success; } } diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs index 094ed305..564bde09 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs @@ -29,5 +29,19 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys return ResultCode.Success; } + + [Command(11)] + // CreateTransferMemoryStorage(b8, u64, handle<copy>) -> object<nn::am::service::IStorage> + public ResultCode CreateTransferMemoryStorage(ServiceCtx context) + { + bool unknown = context.RequestData.ReadBoolean(); + long size = context.RequestData.ReadInt64(); + + // NOTE: We don't support TransferMemory for now. + + MakeObject(context, new IStorage(new byte[size])); + + return ResultCode.Success; + } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletFifo.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletFifo.cs index 2391ba5e..fb16c86e 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletFifo.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletFifo.cs @@ -5,11 +5,26 @@ using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Am.AppletAE { - internal class AppletFifo<T> : IEnumerable<T> + internal class AppletFifo<T> : IAppletFifo<T> { private ConcurrentQueue<T> _dataQueue; - public int Count => _dataQueue.Count; + public event EventHandler DataAvailable; + + public bool IsSynchronized + { + get { return ((ICollection)_dataQueue).IsSynchronized; } + } + + public object SyncRoot + { + get { return ((ICollection)_dataQueue).SyncRoot; } + } + + public int Count + { + get { return _dataQueue.Count; } + } public AppletFifo() { @@ -19,6 +34,22 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE public void Push(T item) { _dataQueue.Enqueue(item); + + DataAvailable?.Invoke(this, null); + } + + public bool TryAdd(T item) + { + try + { + this.Push(item); + + return true; + } + catch + { + return false; + } } public T Pop() @@ -36,6 +67,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE return _dataQueue.TryDequeue(out result); } + public bool TryTake(out T item) + { + return this.TryPop(out item); + } + public T Peek() { if (_dataQueue.TryPeek(out T result)) @@ -66,6 +102,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE _dataQueue.CopyTo(array, arrayIndex); } + public void CopyTo(Array array, int index) + { + this.CopyTo((T[])array, index); + } + public IEnumerator<T> GetEnumerator() { return _dataQueue.GetEnumerator(); diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletSession.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletSession.cs new file mode 100644 index 00000000..6c9197b3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletSession.cs @@ -0,0 +1,77 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE +{ + internal class AppletSession + { + private IAppletFifo<byte[]> _inputData; + private IAppletFifo<byte[]> _outputData; + + public event EventHandler DataAvailable; + + public int Length + { + get { return _inputData.Count; } + } + + public AppletSession() + : this(new AppletFifo<byte[]>(), + new AppletFifo<byte[]>()) + { } + + public AppletSession( + IAppletFifo<byte[]> inputData, + IAppletFifo<byte[]> outputData) + { + _inputData = inputData; + _outputData = outputData; + + _inputData.DataAvailable += OnDataAvailable; + } + + private void OnDataAvailable(object sender, EventArgs e) + { + DataAvailable?.Invoke(this, null); + } + + public void Push(byte[] item) + { + if (!this.TryPush(item)) + { + // TODO(jduncanator): Throw a proper exception + throw new InvalidOperationException(); + } + } + + public bool TryPush(byte[] item) + { + return _outputData.TryAdd(item); + } + + public byte[] Pop() + { + if (this.TryPop(out byte[] item)) + { + return item; + } + + throw new InvalidOperationException("Input data empty."); + } + + public bool TryPop(out byte[] item) + { + return _inputData.TryTake(out item); + } + + /// <summary> + /// This returns an AppletSession that can be used at the + /// other end of the pipe. Pushing data into this new session + /// will put it in the first session's input buffer, and vice + /// versa. + /// </summary> + public AppletSession GetConsumer() + { + return new AppletSession(this._outputData, this._inputData); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAppletFifo.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAppletFifo.cs new file mode 100644 index 00000000..ca79bac7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IAppletFifo.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Am.AppletAE +{ + interface IAppletFifo<T> : IProducerConsumerCollection<T> + { + event EventHandler DataAvailable; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs index 90eb13ce..5013e2e3 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs @@ -24,11 +24,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE // Write(u64, buffer<bytes, 0x21>) public ResultCode Write(ServiceCtx context) { - // TODO: Error conditions. long writePosition = context.RequestData.ReadInt64(); + if (writePosition > _storage.Data.Length) + { + return ResultCode.OutOfBounds; + } + (long position, long size) = context.Request.GetBufferType0x21(); + size = Math.Min(size, _storage.Data.Length - writePosition); + if (size > 0) { long maxSize = _storage.Data.Length - writePosition; @@ -50,23 +56,20 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE // Read(u64) -> buffer<bytes, 0x22> public ResultCode Read(ServiceCtx context) { - // TODO: Error conditions. long readPosition = context.RequestData.ReadInt64(); + if (readPosition > _storage.Data.Length) + { + return ResultCode.OutOfBounds; + } + (long position, long size) = context.Request.GetBufferType0x22(); - byte[] data; + size = Math.Min(size, _storage.Data.Length - readPosition); - if (_storage.Data.Length > size) - { - data = new byte[size]; + byte[] data = new byte[size]; - Buffer.BlockCopy(_storage.Data, 0, data, 0, (int)size); - } - else - { - data = _storage.Data; - } + Buffer.BlockCopy(_storage.Data, (int)readPosition, data, 0, (int)size); context.Memory.WriteBytes(position, data); diff --git a/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs index a5eb42f3..d8979f4a 100644 --- a/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs +++ b/Ryujinx.HLE/HOS/Services/Am/ResultCode.cs @@ -7,8 +7,10 @@ namespace Ryujinx.HLE.HOS.Services.Am Success = 0, + NotAvailable = (2 << ErrorCodeShift) | ModuleId, NoMessages = (3 << ErrorCodeShift) | ModuleId, ObjectInvalid = (500 << ErrorCodeShift) | ModuleId, + OutOfBounds = (503 << ErrorCodeShift) | ModuleId, CpuBoostModeInvalid = (506 << ErrorCodeShift) | ModuleId } }
\ No newline at end of file |
