IpcService.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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(LogClass.KernelIpc, $"{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. string DbgMessage = $"{Context.Session.ServiceName} {Service.GetType().Name}: {CommandId}";
  81. throw new NotImplementedException(DbgMessage);
  82. }
  83. }
  84. protected static void MakeObject(ServiceCtx Context, IpcService Obj)
  85. {
  86. IpcService Service = Context.Session.Service;
  87. if (Service.IsDomain)
  88. {
  89. Context.Response.ResponseObjIds.Add(Service.Add(Obj));
  90. }
  91. else
  92. {
  93. KSession Session = new KSession(Obj, Context.Session.ServiceName);
  94. int Handle = Context.Process.HandleTable.OpenHandle(Session);
  95. Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
  96. }
  97. }
  98. private int Add(IIpcService Obj)
  99. {
  100. return DomainObjects.Add(Obj);
  101. }
  102. private bool Delete(int Id)
  103. {
  104. object Obj = DomainObjects.Delete(Id);
  105. if (Obj is IDisposable DisposableObj)
  106. {
  107. DisposableObj.Dispose();
  108. }
  109. return Obj != null;
  110. }
  111. private IIpcService GetObject(int Id)
  112. {
  113. return DomainObjects.GetData<IIpcService>(Id);
  114. }
  115. }
  116. }