aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Services')
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletCreator/ILibraryAppletAccessor.cs108
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ILibraryAppletCreator.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletFifo.cs45
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AppletSession.cs77
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/IAppletFifo.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorageAccessor.cs27
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/ResultCode.cs2
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