protected static void MakeObject(ServiceCtx context, IpcService obj) { IpcService service = context.Session.Service; if (service._isDomain) { context.Response.ObjectIds.Add(service.Add(obj)); } else { KSession session = new KSession(context.Device.System.KernelContext); session.ClientSession.Service = obj; if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success) { throw new InvalidOperationException("Out of handles!"); } session.ServerSession.DecrementReferenceCount(); session.ClientSession.DecrementReferenceCount(); context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle); } }
protected T GetObject <T>(ServiceCtx context, int index) where T : IpcService { int objId = context.Request.ObjectIds[index]; IpcService obj = _parent.GetObject(objId); return(obj is T t ? t : null); }
public void AddSessionObj(KServerSession serverSession, IpcService obj) { // Ensure that the sever loop is running. InitDone.WaitOne(); _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle); AddSessionObj(serverSessionHandle, obj); }
public void AddSessionObj(int serverSessionHandle, IpcService obj) { _sessionHandles.Add(serverSessionHandle); if (!_sessions.ContainsKey(serverSessionHandle)) { _sessions.Add(serverSessionHandle, obj); } else { _sessions.Remove(serverSessionHandle); _sessions.Add(serverSessionHandle, obj); } }
public IpcService(ServerBase server = null) { Commands = Assembly.GetExecutingAssembly().GetTypes() .Where(type => type == GetType()) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) .SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandAttribute)) .Select(command => (((CommandAttribute)command).Id, methodInfo))) .ToDictionary(command => command.Id, command => command.methodInfo); Server = server; _parent = this; _domainObjects = new IdDictionary(); _selfId = -1; }
protected static void MakeObject(ServiceCtx Context, IpcService Obj) { IpcService Service = Context.Session.Service; if (Service.IsDomain) { Context.Response.ObjectIds.Add(Service.Add(Obj)); } else { KSession Session = new KSession(Obj, Context.Session.ServiceName); int Handle = Context.Process.HandleTable.OpenHandle(Session); Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); } }
protected static T GetObject <T>(ServiceCtx Context, int Index) where T : IpcService { IpcService Service = Context.Session.Service; if (!Service.IsDomain) { int Handle = Context.Request.HandleDesc.ToMove[Index]; KSession Session = Context.Process.HandleTable.GetObject <KSession>(Handle); return(Session?.Service is T ? (T)Session.Service : null); } int ObjId = Context.Request.ObjectIds[Index]; IIpcService Obj = Service.GetObject(ObjId); return(Obj is T ? (T)Obj : null); }
protected static T GetObject <T>(ServiceCtx context, int index) where T : IpcService { IpcService service = context.Session.Service; if (!service._isDomain) { int handle = context.Request.HandleDesc.ToMove[index]; KSession session = context.Process.HandleTable.GetObject <KSession>(handle); return(session?.Service is T ? (T)session.Service : null); } int objId = context.Request.ObjectIds[index]; IIpcService obj = service.GetObject(objId); return(obj is T ? (T)obj : null); }
protected void MakeObject(ServiceCtx context, IpcService obj) { obj.TrySetServer(_parent.Server); if (_parent._isDomain) { obj._parent = _parent; context.Response.ObjectIds.Add(_parent.Add(obj)); } else { context.Device.System.KernelContext.Syscall.CreateSession(false, 0, out int serverSessionHandle, out int clientSessionHandle); obj.Server.AddSessionObj(serverSessionHandle, obj); context.Response.HandleDesc = IpcHandleDesc.MakeMove(clientSessionHandle); } }
protected static void MakeObject(ServiceCtx context, IpcService obj) { IpcService service = context.Session.Service; if (service._isDomain) { context.Response.ObjectIds.Add(service.Add(obj)); } else { KSession session = new KSession(obj, context.Session.ServiceName); if (context.Process.HandleTable.GenerateHandle(session, out int handle) != KernelResult.Success) { throw new InvalidOperationException("Out of handles!"); } context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle); } }
protected static void MakeObject(ServiceCtx Context, IpcService Obj) { IpcService Service = Context.Session.Service; if (Service.IsDomain) { Context.Response.ObjectIds.Add(Service.Add(Obj)); } else { KSession Session = new KSession(Obj, Context.Session.ServiceName); if (Context.Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success) { throw new InvalidOperationException("Out of handles!"); } Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); } }
private void ServerLoop() { _selfProcess = KernelStatic.GetCurrentProcess(); if (SmObjectFactory != null) { _context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle); AddPort(serverPortHandle, SmObjectFactory); InitDone.Set(); } else { InitDone.Dispose(); } KThread thread = KernelStatic.GetCurrentThread(); ulong messagePtr = thread.TlsAddress; _context.Syscall.SetHeapSize(0x200000, out ulong heapAddr); _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10); _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48)); int replyTargetHandle = 0; while (true) { int[] portHandles = _portHandles.ToArray(); int[] sessionHandles = _sessionHandles.ToArray(); int[] handles = new int[portHandles.Length + sessionHandles.Length]; portHandles.CopyTo(handles, 0); sessionHandles.CopyTo(handles, portHandles.Length); // We still need a timeout here to allow the service to pick up and listen new sessions... var rc = _context.Syscall.ReplyAndReceive(handles, replyTargetHandle, 1000000L, out int signaledIndex); thread.HandlePostSyscall(); if (!thread.Context.Running) { break; } replyTargetHandle = 0; if (rc == KernelResult.Success && signaledIndex >= portHandles.Length) { // We got a IPC request, process it, pass to the appropriate service if needed. int signaledHandle = handles[signaledIndex]; if (Process(signaledHandle, heapAddr)) { replyTargetHandle = signaledHandle; } } else { if (rc == KernelResult.Success) { // We got a new connection, accept the session to allow servicing future requests. if (_context.Syscall.AcceptSession(handles[signaledIndex], out int serverSessionHandle) == KernelResult.Success) { IpcService obj = _ports[handles[signaledIndex]].Invoke(); AddSessionObj(serverSessionHandle, obj); } } _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10); _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48)); } } }
public void AddSessionObj(int serverSessionHandle, IpcService obj) { _sessionHandles.Add(serverSessionHandle); _sessions.Add(serverSessionHandle, obj); }
public void AddSessionObj(KServerSession serverSession, IpcService obj) { _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle); AddSessionObj(serverSessionHandle, obj); }
private bool Process(int serverSessionHandle, ulong recvListAddr) { KProcess process = KernelStatic.GetCurrentProcess(); KThread thread = KernelStatic.GetCurrentThread(); ulong messagePtr = thread.TlsAddress; ulong messageSize = 0x100; byte[] reqData = new byte[messageSize]; process.CpuMemory.Read(messagePtr, reqData); IpcMessage request = new IpcMessage(reqData, (long)messagePtr); IpcMessage response = new IpcMessage(); ulong tempAddr = recvListAddr; int sizesOffset = request.RawData.Length - ((request.RecvListBuff.Count * 2 + 3) & ~3); bool noReceive = true; for (int i = 0; i < request.ReceiveBuff.Count; i++) { noReceive &= (request.ReceiveBuff[i].Position == 0); } if (noReceive) { for (int i = 0; i < request.RecvListBuff.Count; i++) { ulong size = (ulong)BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan().Slice(sizesOffset + i * 2, 2)); response.PtrBuff.Add(new IpcPtrBuffDesc(tempAddr, (uint)i, size)); request.RecvListBuff[i] = new IpcRecvListBuffDesc(tempAddr, size); tempAddr += size; } } bool shouldReply = true; bool isTipcCommunication = false; using (MemoryStream raw = new MemoryStream(request.RawData)) { BinaryReader reqReader = new BinaryReader(raw); if (request.Type == IpcMessageType.HipcRequest || request.Type == IpcMessageType.HipcRequestWithContext) { response.Type = IpcMessageType.HipcResponse; using (MemoryStream resMs = new MemoryStream()) { BinaryWriter resWriter = new BinaryWriter(resMs); ServiceCtx context = new ServiceCtx( _context.Device, process, process.CpuMemory, thread, request, response, reqReader, resWriter); _sessions[serverSessionHandle].CallHipcMethod(context); response.RawData = resMs.ToArray(); } } else if (request.Type == IpcMessageType.HipcControl || request.Type == IpcMessageType.HipcControlWithContext) { uint magic = (uint)reqReader.ReadUInt64(); uint cmdId = (uint)reqReader.ReadUInt64(); switch (cmdId) { case 0: request = FillResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain()); break; case 3: request = FillResponse(response, 0, PointerBufferSize); break; // TODO: Whats the difference between IpcDuplicateSession/Ex? case 2: case 4: int unknown = reqReader.ReadInt32(); _context.Syscall.CreateSession(false, 0, out int dupServerSessionHandle, out int dupClientSessionHandle); AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]); response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle); request = FillResponse(response, 0); break; default: throw new NotImplementedException(cmdId.ToString()); } } else if (request.Type == IpcMessageType.HipcCloseSession || request.Type == IpcMessageType.TipcCloseSession) { _context.Syscall.CloseHandle(serverSessionHandle); _sessionHandles.Remove(serverSessionHandle); IpcService service = _sessions[serverSessionHandle]; if (service is IDisposable disposableObj) { disposableObj.Dispose(); } _sessions.Remove(serverSessionHandle); shouldReply = false; } // If the type is past 0xF, we are using TIPC else if (request.Type > IpcMessageType.TipcCloseSession) { isTipcCommunication = true; // Response type is always the same as request on TIPC. response.Type = request.Type; using (MemoryStream resMs = new MemoryStream()) { BinaryWriter resWriter = new BinaryWriter(resMs); ServiceCtx context = new ServiceCtx( _context.Device, process, process.CpuMemory, thread, request, response, reqReader, resWriter); _sessions[serverSessionHandle].CallTipcMethod(context); response.RawData = resMs.ToArray(); } process.CpuMemory.Write(messagePtr, response.GetBytesTipc()); } else { throw new NotImplementedException(request.Type.ToString()); } if (!isTipcCommunication) { process.CpuMemory.Write(messagePtr, response.GetBytes((long)messagePtr, recvListAddr | ((ulong)PointerBufferSize << 48))); } return(shouldReply); } }
private void AddPort(int serverPortHandle, IpcService obj) { _portHandles.Add(serverPortHandle); _ports.Add(serverPortHandle, obj); }
public void CallMethod(ServiceCtx context) { IpcService service = this; if (_isDomain) { int domainWord0 = context.RequestData.ReadInt32(); int domainObjId = context.RequestData.ReadInt32(); int domainCmd = (domainWord0 >> 0) & 0xff; int inputObjCount = (domainWord0 >> 8) & 0xff; int dataPayloadSize = (domainWord0 >> 16) & 0xffff; context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin); for (int index = 0; index < inputObjCount; index++) { context.Request.ObjectIds.Add(context.RequestData.ReadInt32()); } context.RequestData.BaseStream.Seek(0x10, SeekOrigin.Begin); if (domainCmd == 1) { service = GetObject(domainObjId); context.ResponseData.Write(0L); context.ResponseData.Write(0L); } else if (domainCmd == 2) { Delete(domainObjId); context.ResponseData.Write(0L); return; } else { throw new NotImplementedException($"Domain command: {domainCmd}"); } } long sfciMagic = context.RequestData.ReadInt64(); int commandId = (int)context.RequestData.ReadInt64(); bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest); if (ServiceConfiguration.IgnoreMissingServices || serviceExists) { ResultCode result = ResultCode.Success; context.ResponseData.BaseStream.Seek(_isDomain ? 0x20 : 0x10, SeekOrigin.Begin); if (serviceExists) { Logger.Debug?.Print(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}"); result = (ResultCode)processRequest.Invoke(service, new object[] { context }); } else { string serviceName; DummyService dummyService = service as DummyService; serviceName = (dummyService == null) ? service.GetType().FullName : dummyService.ServiceName; Logger.Warning?.Print(LogClass.KernelIpc, $"Missing service {serviceName}: {commandId} ignored"); } if (_isDomain) { foreach (int id in context.Response.ObjectIds) { context.ResponseData.Write(id); } context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin); context.ResponseData.Write(context.Response.ObjectIds.Count); } context.ResponseData.BaseStream.Seek(_isDomain ? 0x10 : 0, SeekOrigin.Begin); context.ResponseData.Write(IpcMagic.Sfco); context.ResponseData.Write((long)result); } else { string dbgMessage = $"{service.GetType().FullName}: {commandId}"; throw new ServiceNotImplementedException(service, context, dbgMessage); } }
private int Add(IpcService obj) { return(_domainObjects.Add(obj)); }
public void SetParent(IpcService parent) { _parent = parent._parent; }