using ChocolArm64.Memory; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; using System; using System.Collections.Concurrent; namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel { class NvHostChannelIoctl { private class ChannelsPerProcess { public ConcurrentDictionary Channels { get; private set; } public ChannelsPerProcess() { Channels = new ConcurrentDictionary(); Channels.TryAdd(NvChannelName.Gpu, new NvChannel()); } } private static ConcurrentDictionary Channels; static NvHostChannelIoctl() { Channels = new ConcurrentDictionary(); } public static int ProcessIoctlGpu(ServiceCtx Context, int Cmd) { return ProcessIoctl(Context, NvChannelName.Gpu, Cmd); } public static int ProcessIoctl(ServiceCtx Context, NvChannelName Channel, int Cmd) { switch (Cmd & 0xffff) { case 0x4714: return SetUserData (Context); case 0x4801: return SetNvMap (Context); case 0x4803: return SetTimeout (Context, Channel); case 0x4808: return SubmitGpfifo (Context); case 0x4809: return AllocObjCtx (Context); case 0x480b: return ZcullBind (Context); case 0x480c: return SetErrorNotifier (Context); case 0x480d: return SetPriority (Context); case 0x481a: return AllocGpfifoEx2 (Context); case 0x481b: return KickoffPbWithAttr(Context); } throw new NotImplementedException(Cmd.ToString("x8")); } private static int SetUserData(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int SetNvMap(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int SetTimeout(ServiceCtx Context, NvChannelName Channel) { long InputPosition = Context.Request.GetBufferType0x21().Position; GetChannel(Context, Channel).Timeout = Context.Memory.ReadInt32(InputPosition); return NvResult.Success; } private static int SubmitGpfifo(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;; for (int Index = 0; Index < Args.NumEntries; Index++) { long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8); PushGpfifo(Context, Vmm, Gpfifo); } Args.SyncptId = 0; Args.SyncptValue = 0; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); return NvResult.Success; } private static int AllocObjCtx(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int ZcullBind(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int SetErrorNotifier(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int SetPriority(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int AllocGpfifoEx2(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv, "Stubbed."); return NvResult.Success; } private static int KickoffPbWithAttr(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; NvHostChannelSubmitGpfifo Args = AMemoryHelper.Read(Context.Memory, InputPosition); NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;; for (int Index = 0; Index < Args.NumEntries; Index++) { long Gpfifo = Context.Memory.ReadInt64(Args.Address + Index * 8); PushGpfifo(Context, Vmm, Gpfifo); } Args.SyncptId = 0; Args.SyncptValue = 0; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); return NvResult.Success; } private static void PushGpfifo(ServiceCtx Context, NvGpuVmm Vmm, long Gpfifo) { long VA = Gpfifo & 0xff_ffff_ffff; int Size = (int)(Gpfifo >> 40) & 0x7ffffc; byte[] Data = Vmm.ReadBytes(VA, Size); NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data); Context.Device.Gpu.Fifo.PushBuffer(Vmm, PushBuffer); } public static NvChannel GetChannel(ServiceCtx Context, NvChannelName Channel) { ChannelsPerProcess Cpp = Channels.GetOrAdd(Context.Process, (Key) => { return new ChannelsPerProcess(); }); return Cpp.Channels[Channel]; } public static void UnloadProcess(Process Process) { Channels.TryRemove(Process, out _); } } }