ILibraryAppletAccessor.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.HLE.HOS.Applets;
  3. using Ryujinx.HLE.HOS.Ipc;
  4. using Ryujinx.HLE.HOS.Kernel;
  5. using Ryujinx.HLE.HOS.Kernel.Common;
  6. using Ryujinx.HLE.HOS.Kernel.Threading;
  7. using System;
  8. namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletCreator
  9. {
  10. class ILibraryAppletAccessor : DisposableIpcService
  11. {
  12. private KernelContext _kernelContext;
  13. private IApplet _applet;
  14. private AppletSession _normalSession;
  15. private AppletSession _interactiveSession;
  16. private KEvent _stateChangedEvent;
  17. private KEvent _normalOutDataEvent;
  18. private KEvent _interactiveOutDataEvent;
  19. private int _stateChangedEventHandle;
  20. private int _normalOutDataEventHandle;
  21. private int _interactiveOutDataEventHandle;
  22. private int _indirectLayerHandle;
  23. public ILibraryAppletAccessor(AppletId appletId, Horizon system)
  24. {
  25. _kernelContext = system.KernelContext;
  26. _stateChangedEvent = new KEvent(system.KernelContext);
  27. _normalOutDataEvent = new KEvent(system.KernelContext);
  28. _interactiveOutDataEvent = new KEvent(system.KernelContext);
  29. _applet = AppletManager.Create(appletId, system);
  30. _normalSession = new AppletSession();
  31. _interactiveSession = new AppletSession();
  32. _applet.AppletStateChanged += OnAppletStateChanged;
  33. _normalSession.DataAvailable += OnNormalOutData;
  34. _interactiveSession.DataAvailable += OnInteractiveOutData;
  35. Logger.Info?.Print(LogClass.ServiceAm, $"Applet '{appletId}' created.");
  36. }
  37. private void OnAppletStateChanged(object sender, EventArgs e)
  38. {
  39. _stateChangedEvent.WritableEvent.Signal();
  40. }
  41. private void OnNormalOutData(object sender, EventArgs e)
  42. {
  43. _normalOutDataEvent.WritableEvent.Signal();
  44. }
  45. private void OnInteractiveOutData(object sender, EventArgs e)
  46. {
  47. _interactiveOutDataEvent.WritableEvent.Signal();
  48. }
  49. [CommandHipc(0)]
  50. // GetAppletStateChangedEvent() -> handle<copy>
  51. public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
  52. {
  53. if (_stateChangedEventHandle == 0)
  54. {
  55. if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != KernelResult.Success)
  56. {
  57. throw new InvalidOperationException("Out of handles!");
  58. }
  59. }
  60. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangedEventHandle);
  61. return ResultCode.Success;
  62. }
  63. [CommandHipc(10)]
  64. // Start()
  65. public ResultCode Start(ServiceCtx context)
  66. {
  67. return (ResultCode)_applet.Start(_normalSession.GetConsumer(), _interactiveSession.GetConsumer());
  68. }
  69. [CommandHipc(20)]
  70. // RequestExit()
  71. public ResultCode RequestExit(ServiceCtx context)
  72. {
  73. // TODO: Since we don't support software Applet for now, we can just signals the changed state of the applet.
  74. _stateChangedEvent.ReadableEvent.Signal();
  75. Logger.Stub?.PrintStub(LogClass.ServiceAm);
  76. return ResultCode.Success;
  77. }
  78. [CommandHipc(30)]
  79. // GetResult()
  80. public ResultCode GetResult(ServiceCtx context)
  81. {
  82. return (ResultCode)_applet.GetResult();
  83. }
  84. [CommandHipc(60)]
  85. // PresetLibraryAppletGpuTimeSliceZero()
  86. public ResultCode PresetLibraryAppletGpuTimeSliceZero(ServiceCtx context)
  87. {
  88. // NOTE: This call reset two internal fields to 0 and one internal field to "true".
  89. // It seems to be used only with software keyboard inline.
  90. // Since we doesn't support applets for now, it's fine to stub it.
  91. Logger.Stub?.PrintStub(LogClass.ServiceAm);
  92. return ResultCode.Success;
  93. }
  94. [CommandHipc(100)]
  95. // PushInData(object<nn::am::service::IStorage>)
  96. public ResultCode PushInData(ServiceCtx context)
  97. {
  98. IStorage data = GetObject<IStorage>(context, 0);
  99. _normalSession.Push(data.Data);
  100. return ResultCode.Success;
  101. }
  102. [CommandHipc(101)]
  103. // PopOutData() -> object<nn::am::service::IStorage>
  104. public ResultCode PopOutData(ServiceCtx context)
  105. {
  106. if(_normalSession.TryPop(out byte[] data))
  107. {
  108. MakeObject(context, new IStorage(data));
  109. _normalOutDataEvent.WritableEvent.Clear();
  110. return ResultCode.Success;
  111. }
  112. return ResultCode.NotAvailable;
  113. }
  114. [CommandHipc(103)]
  115. // PushInteractiveInData(object<nn::am::service::IStorage>)
  116. public ResultCode PushInteractiveInData(ServiceCtx context)
  117. {
  118. IStorage data = GetObject<IStorage>(context, 0);
  119. _interactiveSession.Push(data.Data);
  120. return ResultCode.Success;
  121. }
  122. [CommandHipc(104)]
  123. // PopInteractiveOutData() -> object<nn::am::service::IStorage>
  124. public ResultCode PopInteractiveOutData(ServiceCtx context)
  125. {
  126. if(_interactiveSession.TryPop(out byte[] data))
  127. {
  128. MakeObject(context, new IStorage(data));
  129. _interactiveOutDataEvent.WritableEvent.Clear();
  130. return ResultCode.Success;
  131. }
  132. return ResultCode.NotAvailable;
  133. }
  134. [CommandHipc(105)]
  135. // GetPopOutDataEvent() -> handle<copy>
  136. public ResultCode GetPopOutDataEvent(ServiceCtx context)
  137. {
  138. if (_normalOutDataEventHandle == 0)
  139. {
  140. if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != KernelResult.Success)
  141. {
  142. throw new InvalidOperationException("Out of handles!");
  143. }
  144. }
  145. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_normalOutDataEventHandle);
  146. return ResultCode.Success;
  147. }
  148. [CommandHipc(106)]
  149. // GetPopInteractiveOutDataEvent() -> handle<copy>
  150. public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
  151. {
  152. if (_interactiveOutDataEventHandle == 0)
  153. {
  154. if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != KernelResult.Success)
  155. {
  156. throw new InvalidOperationException("Out of handles!");
  157. }
  158. }
  159. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_interactiveOutDataEventHandle);
  160. return ResultCode.Success;
  161. }
  162. [CommandHipc(110)]
  163. // NeedsToExitProcess()
  164. public ResultCode NeedsToExitProcess(ServiceCtx context)
  165. {
  166. return ResultCode.Stubbed;
  167. }
  168. [CommandHipc(150)]
  169. // RequestForAppletToGetForeground()
  170. public ResultCode RequestForAppletToGetForeground(ServiceCtx context)
  171. {
  172. return ResultCode.Stubbed;
  173. }
  174. [CommandHipc(160)] // 2.0.0+
  175. // GetIndirectLayerConsumerHandle() -> u64 indirect_layer_consumer_handle
  176. public ResultCode GetIndirectLayerConsumerHandle(ServiceCtx context)
  177. {
  178. Horizon horizon = _kernelContext.Device.System;
  179. _indirectLayerHandle = horizon.AppletState.IndirectLayerHandles.Add(_applet);
  180. context.ResponseData.Write((ulong)_indirectLayerHandle);
  181. return ResultCode.Success;
  182. }
  183. protected override void Dispose(bool isDisposing)
  184. {
  185. if (isDisposing)
  186. {
  187. if (_stateChangedEventHandle != 0)
  188. {
  189. _kernelContext.Syscall.CloseHandle(_stateChangedEventHandle);
  190. }
  191. if (_normalOutDataEventHandle != 0)
  192. {
  193. _kernelContext.Syscall.CloseHandle(_normalOutDataEventHandle);
  194. }
  195. if (_interactiveOutDataEventHandle != 0)
  196. {
  197. _kernelContext.Syscall.CloseHandle(_interactiveOutDataEventHandle);
  198. }
  199. }
  200. Horizon horizon = _kernelContext.Device.System;
  201. horizon.AppletState.IndirectLayerHandles.Delete(_indirectLayerHandle);
  202. }
  203. }
  204. }