IApplicationFunctions.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.HLE.HOS.Ipc;
  3. using Ryujinx.HLE.HOS.Kernel.Common;
  4. using Ryujinx.HLE.HOS.Kernel.Threading;
  5. using Ryujinx.HLE.HOS.Services.Am.AppletAE;
  6. using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage;
  7. using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService;
  8. using Ryujinx.HLE.Utilities;
  9. using System;
  10. namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy
  11. {
  12. class IApplicationFunctions : IpcService
  13. {
  14. private KEvent _gpuErrorDetectedSystemEvent;
  15. public IApplicationFunctions(Horizon system)
  16. {
  17. _gpuErrorDetectedSystemEvent = new KEvent(system);
  18. }
  19. [Command(1)]
  20. // PopLaunchParameter(u32) -> object<nn::am::service::IStorage>
  21. public ResultCode PopLaunchParameter(ServiceCtx context)
  22. {
  23. // Only the first 0x18 bytes of the Data seems to be actually used.
  24. MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams()));
  25. return ResultCode.Success;
  26. }
  27. [Command(20)]
  28. // EnsureSaveData(nn::account::Uid) -> u64
  29. public ResultCode EnsureSaveData(ServiceCtx context)
  30. {
  31. UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
  32. context.ResponseData.Write(0L);
  33. Logger.PrintStub(LogClass.ServiceAm, new { userId });
  34. return ResultCode.Success;
  35. }
  36. [Command(21)]
  37. // GetDesiredLanguage() -> nn::settings::LanguageCode
  38. public ResultCode GetDesiredLanguage(ServiceCtx context)
  39. {
  40. context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode);
  41. return ResultCode.Success;
  42. }
  43. [Command(22)]
  44. // SetTerminateResult(u32)
  45. public ResultCode SetTerminateResult(ServiceCtx context)
  46. {
  47. int errorCode = context.RequestData.ReadInt32();
  48. string result = GetFormattedErrorCode(errorCode);
  49. Logger.PrintInfo(LogClass.ServiceAm, $"Result = 0x{errorCode:x8} ({result}).");
  50. return ResultCode.Success;
  51. }
  52. private string GetFormattedErrorCode(int errorCode)
  53. {
  54. int module = (errorCode >> 0) & 0x1ff;
  55. int description = (errorCode >> 9) & 0x1fff;
  56. return $"{(2000 + module):d4}-{description:d4}";
  57. }
  58. [Command(23)]
  59. // GetDisplayVersion() -> nn::oe::DisplayVersion
  60. public ResultCode GetDisplayVersion(ServiceCtx context)
  61. {
  62. // FIXME: Need to check correct version on a switch.
  63. context.ResponseData.Write(1L);
  64. context.ResponseData.Write(0L);
  65. return ResultCode.Success;
  66. }
  67. [Command(40)]
  68. // NotifyRunning() -> b8
  69. public ResultCode NotifyRunning(ServiceCtx context)
  70. {
  71. context.ResponseData.Write(1);
  72. return ResultCode.Success;
  73. }
  74. [Command(50)] // 2.0.0+
  75. // GetPseudoDeviceId() -> nn::util::Uuid
  76. public ResultCode GetPseudoDeviceId(ServiceCtx context)
  77. {
  78. context.ResponseData.Write(0L);
  79. context.ResponseData.Write(0L);
  80. Logger.PrintStub(LogClass.ServiceAm);
  81. return ResultCode.Success;
  82. }
  83. [Command(66)] // 3.0.0+
  84. // InitializeGamePlayRecording(u64, handle<copy>)
  85. public ResultCode InitializeGamePlayRecording(ServiceCtx context)
  86. {
  87. Logger.PrintStub(LogClass.ServiceAm);
  88. return ResultCode.Success;
  89. }
  90. [Command(67)] // 3.0.0+
  91. // SetGamePlayRecordingState(u32)
  92. public ResultCode SetGamePlayRecordingState(ServiceCtx context)
  93. {
  94. int state = context.RequestData.ReadInt32();
  95. Logger.PrintStub(LogClass.ServiceAm, new { state });
  96. return ResultCode.Success;
  97. }
  98. [Command(110)] // 5.0.0+
  99. // QueryApplicationPlayStatistics(buffer<bytes, 5> title_id_list) -> (buffer<bytes, 6> entries, s32 entries_count)
  100. public ResultCode QueryApplicationPlayStatistics(ServiceCtx context)
  101. {
  102. // TODO: Call pdm:qry cmd 13 when IPC call between services will be implemented.
  103. return (ResultCode)QueryPlayStatisticsManager.GetPlayStatistics(context);
  104. }
  105. [Command(111)] // 6.0.0+
  106. // QueryApplicationPlayStatisticsByUid(nn::account::Uid, buffer<bytes, 5> title_id_list) -> (buffer<bytes, 6> entries, s32 entries_count)
  107. public ResultCode QueryApplicationPlayStatisticsByUid(ServiceCtx context)
  108. {
  109. // TODO: Call pdm:qry cmd 16 when IPC call between services will be implemented.
  110. return (ResultCode)QueryPlayStatisticsManager.GetPlayStatistics(context, true);
  111. }
  112. [Command(130)] // 8.0.0+
  113. // GetGpuErrorDetectedSystemEvent() -> handle<copy>
  114. public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context)
  115. {
  116. if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out int gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
  117. {
  118. throw new InvalidOperationException("Out of handles!");
  119. }
  120. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(gpuErrorDetectedSystemEventHandle);
  121. // NOTE: This is used by "sdk" NSO during applet-application initialization.
  122. // A seperate thread is setup where event-waiting is handled.
  123. // When the Event is signaled, official sw will assert.
  124. return ResultCode.Success;
  125. }
  126. }
  127. }