ILibraryAppletAccessor.cs 8.7 KB

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