IpcService.cs 4.1 KB

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