Ryujinx/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs

215 lines
7.3 KiB
C#

using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices;
using System;
using System.IO;
namespace Ryujinx.Core.OsHle.Ipc
{
static class IpcHandler
{
private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
public static void IpcCall(
Switch Ns,
Process Process,
AMemory Memory,
HSession Session,
IpcMessage Request,
int ThreadId,
long CmdPtr,
int HndId)
{
IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request);
using (MemoryStream Raw = new MemoryStream(Request.RawData))
{
BinaryReader ReqReader = new BinaryReader(Raw);
if (Request.Type == IpcMessageType.Request)
{
string ServiceName = Session.Service.GetType().Name;
ServiceProcessRequest ProcReq = null;
bool IgnoreNullPR = false;
string DbgServiceName = string.Empty;
if (Session is HDomain Dom)
{
if (Request.DomCmd == IpcDomCmd.SendMsg)
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
object Obj = Dom.GetObject(Request.DomObjId);
if (Obj is HDomain)
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else if (Obj != null)
{
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
{
Dom.Delete(Request.DomObjId);
Response = FillResponse(Response, 0);
IgnoreNullPR = true;
}
}
else
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
if (Session is HSessionObj)
{
object Obj = ((HSessionObj)Session).Obj;
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
Logging.Debug($"IpcMessage: {DbgServiceName}");
if (ProcReq != null)
{
using (MemoryStream ResMS = new MemoryStream())
{
BinaryWriter ResWriter = new BinaryWriter(ResMS);
ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
long Result = ProcReq(Context);
Response = FillResponse(Response, Result, ResMS.ToArray());
}
}
else if (!IgnoreNullPR)
{
throw new NotImplementedException(DbgServiceName);
}
}
else if (Request.Type == IpcMessageType.Control)
{
long Magic = ReqReader.ReadInt64();
long CmdId = ReqReader.ReadInt64();
switch (CmdId)
{
case 0:
{
HDomain Dom = new HDomain(Session);
Process.HandleTable.ReplaceData(HndId, Dom);
Request = FillResponse(Response, 0, Dom.Add(Dom));
break;
}
case 3:
{
Request = FillResponse(Response, 0, 0x500);
break;
}
//TODO: Whats the difference between IpcDuplicateSession/Ex?
case 2:
case 4:
{
int Unknown = ReqReader.ReadInt32();
int Handle = Process.HandleTable.OpenHandle(Session);
Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
Request = FillResponse(Response, 0);
break;
}
default: throw new NotImplementedException(CmdId.ToString());
}
}
else if (Request.Type == IpcMessageType.CloseSession)
{
//TODO
}
else
{
throw new NotImplementedException(Request.Type.ToString());
}
AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr));
}
}
private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
{
using (MemoryStream MS = new MemoryStream())
{
BinaryWriter Writer = new BinaryWriter(MS);
foreach (int Value in Values)
{
Writer.Write(Value);
}
return FillResponse(Response, Result, MS.ToArray());
}
}
private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null)
{
Response.Type = IpcMessageType.Response;
using (MemoryStream MS = new MemoryStream())
{
BinaryWriter Writer = new BinaryWriter(MS);
Writer.Write(SfcoMagic);
Writer.Write(Result);
if (Data != null)
{
Writer.Write(Data);
}
Response.RawData = MS.ToArray();
}
return Response;
}
}
}