IpcService.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. using Ryujinx.HLE.Logging;
  2. using Ryujinx.HLE.OsHle.Handles;
  3. using Ryujinx.HLE.OsHle.Ipc;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. namespace Ryujinx.HLE.OsHle.Services
  8. {
  9. abstract class IpcService : IIpcService
  10. {
  11. public abstract IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
  12. private IdDictionary DomainObjects;
  13. private int SelfId;
  14. private bool IsDomain;
  15. public IpcService()
  16. {
  17. DomainObjects = new IdDictionary();
  18. SelfId = -1;
  19. }
  20. public int ConvertToDomain()
  21. {
  22. if (SelfId == -1)
  23. {
  24. SelfId = DomainObjects.Add(this);
  25. }
  26. IsDomain = true;
  27. return SelfId;
  28. }
  29. public void ConvertToSession()
  30. {
  31. IsDomain = false;
  32. }
  33. public void CallMethod(ServiceCtx Context)
  34. {
  35. IIpcService Service = this;
  36. if (IsDomain)
  37. {
  38. int DomainWord0 = Context.RequestData.ReadInt32();
  39. int DomainObjId = Context.RequestData.ReadInt32();
  40. long Padding = Context.RequestData.ReadInt64();
  41. int DomainCmd = DomainWord0 & 0xff;
  42. if (DomainCmd == 1)
  43. {
  44. Service = GetObject(DomainObjId);
  45. Context.ResponseData.Write(0L);
  46. Context.ResponseData.Write(0L);
  47. }
  48. else if (DomainCmd == 2)
  49. {
  50. Delete(DomainObjId);
  51. Context.ResponseData.Write(0L);
  52. return;
  53. }
  54. else
  55. {
  56. throw new NotImplementedException($"Domain command: {DomainCmd}");
  57. }
  58. }
  59. long SfciMagic = Context.RequestData.ReadInt64();
  60. int CommandId = (int)Context.RequestData.ReadInt64();
  61. if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest))
  62. {
  63. Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin);
  64. Context.Ns.Log.PrintDebug(LogClass.KernelIpc, $"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
  65. long Result = ProcessRequest(Context);
  66. if (IsDomain)
  67. {
  68. foreach (int Id in Context.Response.ResponseObjIds)
  69. {
  70. Context.ResponseData.Write(Id);
  71. }
  72. Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin);
  73. Context.ResponseData.Write(Context.Response.ResponseObjIds.Count);
  74. }
  75. Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin);
  76. Context.ResponseData.Write(IpcMagic.Sfco);
  77. Context.ResponseData.Write(Result);
  78. }
  79. else
  80. {
  81. string DbgMessage = $"{Context.Session.ServiceName} {Service.GetType().Name}: {CommandId}";
  82. throw new NotImplementedException(DbgMessage);
  83. }
  84. }
  85. protected static void MakeObject(ServiceCtx Context, IpcService Obj)
  86. {
  87. IpcService Service = Context.Session.Service;
  88. if (Service.IsDomain)
  89. {
  90. Context.Response.ResponseObjIds.Add(Service.Add(Obj));
  91. }
  92. else
  93. {
  94. KSession Session = new KSession(Obj, Context.Session.ServiceName);
  95. int Handle = Context.Process.HandleTable.OpenHandle(Session);
  96. Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
  97. }
  98. }
  99. private int Add(IIpcService Obj)
  100. {
  101. return DomainObjects.Add(Obj);
  102. }
  103. private bool Delete(int Id)
  104. {
  105. object Obj = DomainObjects.Delete(Id);
  106. if (Obj is IDisposable DisposableObj)
  107. {
  108. DisposableObj.Dispose();
  109. }
  110. return Obj != null;
  111. }
  112. private IIpcService GetObject(int Id)
  113. {
  114. return DomainObjects.GetData<IIpcService>(Id);
  115. }
  116. }
  117. }