Rewrite nvservices (#800)

* Start rewriting nvservices internals

TODO:

- nvgpu device interface
- nvhost generic device interface

* Some clean up and fixes

- Make sure to remove the fd of a closed channel.
- NvFileDevice now doesn't implement Disposable as it was never used.
- Rename NvHostCtrlGetConfigurationArgument to GetConfigurationArguments
to follow calling convention.
- Make sure to check every ioctls magic.

* Finalize migration for ioctl standard variant

TODO: ioctl2 migration

* Implement SubmitGpfifoEx and fix nvdec

* Implement Ioctl3

* Implement some ioctl3 required by recent games

* Remove unused code and outdated comments

* Return valid event handles with QueryEvent

Also add an exception for unimplemented event ids.

This commit doesn't implement accurately the events, this only define
different events for different event ids.

* Rename all occurance of FileDevice to DeviceFile

* Restub SetClientPid to not cause regressions

* Address comments

* Remove GlobalStateTable

* Address comments

* Align variables in ioctl3

* Some missing alignments

* GetVaRegionsArguments realign

* Make Owner public in NvDeviceFile

* Address LDj3SNuD's comments
This commit is contained in:
Thomas Guillemard 2019-11-02 23:47:56 +01:00 committed by jduncanator
parent c414a356a0
commit be9b9c7cdf
75 changed files with 2798 additions and 2005 deletions

View file

@ -0,0 +1,347 @@
using ARMeilleure.Memory;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics;
using Ryujinx.Graphics.Memory;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
class NvHostChannelDeviceFile : NvDeviceFile
{
private uint _timeout;
private uint _submitTimeout;
private uint _timeslice;
private NvGpu _gpu;
private MemoryManager _memory;
public NvHostChannelDeviceFile(ServiceCtx context) : base(context)
{
_gpu = context.Device.Gpu;
_memory = context.Memory;
_timeout = 3000;
_submitTimeout = 0;
_timeslice = 0;
}
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
{
NvInternalResult result = NvInternalResult.NotImplemented;
if (command.Type == NvIoctl.NvHostCustomMagic)
{
switch (command.Number)
{
case 0x01:
result = Submit(arguments);
break;
case 0x02:
result = CallIoctlMethod<GetParameterArguments>(GetSyncpoint, arguments);
break;
case 0x03:
result = CallIoctlMethod<GetParameterArguments>(GetWaitBase, arguments);
break;
case 0x07:
result = CallIoctlMethod<uint>(SetSubmitTimeout, arguments);
break;
case 0x09:
result = MapCommandBuffer(arguments);
break;
case 0x0a:
result = UnmapCommandBuffer(arguments);
break;
}
}
else if (command.Type == NvIoctl.NvHostMagic)
{
switch (command.Number)
{
case 0x01:
result = CallIoctlMethod<int>(SetNvMapFd, arguments);
break;
case 0x03:
result = CallIoctlMethod<uint>(SetTimeout, arguments);
break;
case 0x08:
result = SubmitGpfifo(arguments);
break;
case 0x09:
result = CallIoctlMethod<AllocObjCtxArguments>(AllocObjCtx, arguments);
break;
case 0x0b:
result = CallIoctlMethod<ZcullBindArguments>(ZcullBind, arguments);
break;
case 0x0c:
result = CallIoctlMethod<SetErrorNotifierArguments>(SetErrorNotifier, arguments);
break;
case 0x0d:
result = CallIoctlMethod<NvChannelPriority>(SetPriority, arguments);
break;
case 0x18:
result = CallIoctlMethod<AllocGpfifoExArguments>(AllocGpfifoEx, arguments);
break;
case 0x1a:
result = CallIoctlMethod<AllocGpfifoExArguments>(AllocGpfifoEx2, arguments);
break;
case 0x1d:
result = CallIoctlMethod<uint>(SetTimeslice, arguments);
break;
}
}
else if (command.Type == NvIoctl.NvGpuMagic)
{
switch (command.Number)
{
case 0x14:
result = CallIoctlMethod<ulong>(SetUserData, arguments);
break;
}
}
return result;
}
private NvInternalResult Submit(Span<byte> arguments)
{
int headerSize = Unsafe.SizeOf<SubmitArguments>();
SubmitArguments submitHeader = MemoryMarshal.Cast<byte, SubmitArguments>(arguments)[0];
Span<CommandBuffer> commandBufferEntries = MemoryMarshal.Cast<byte, CommandBuffer>(arguments.Slice(headerSize)).Slice(0, submitHeader.CmdBufsCount);
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
foreach (CommandBuffer commandBufferEntry in commandBufferEntries)
{
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MemoryId);
int[] commandBufferData = new int[commandBufferEntry.WordsCount];
for (int offset = 0; offset < commandBufferData.Length; offset++)
{
commandBufferData[offset] = _memory.ReadInt32(map.Address + commandBufferEntry.Offset + offset * 4);
}
_gpu.PushCommandBuffer(vmm, commandBufferData);
}
return NvInternalResult.Success;
}
private NvInternalResult GetSyncpoint(ref GetParameterArguments arguments)
{
arguments.Value = 0;
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult GetWaitBase(ref GetParameterArguments arguments)
{
arguments.Value = 0;
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult SetSubmitTimeout(ref uint submitTimeout)
{
_submitTimeout = submitTimeout;
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult MapCommandBuffer(Span<byte> arguments)
{
int headerSize = Unsafe.SizeOf<MapCommandBufferArguments>();
MapCommandBufferArguments commandBufferHeader = MemoryMarshal.Cast<byte, MapCommandBufferArguments>(arguments)[0];
Span<CommandBufferHandle> commandBufferEntries = MemoryMarshal.Cast<byte, CommandBufferHandle>(arguments.Slice(headerSize)).Slice(0, commandBufferHeader.NumEntries);
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
{
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);
if (map == null)
{
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");
return NvInternalResult.InvalidInput;
}
lock (map)
{
if (map.DmaMapAddress == 0)
{
map.DmaMapAddress = vmm.MapLow(map.Address, map.Size);
}
commandBufferEntry.MapAddress = (int)map.DmaMapAddress;
}
}
return NvInternalResult.Success;
}
private NvInternalResult UnmapCommandBuffer(Span<byte> arguments)
{
int headerSize = Unsafe.SizeOf<MapCommandBufferArguments>();
MapCommandBufferArguments commandBufferHeader = MemoryMarshal.Cast<byte, MapCommandBufferArguments>(arguments)[0];
Span<CommandBufferHandle> commandBufferEntries = MemoryMarshal.Cast<byte, CommandBufferHandle>(arguments.Slice(headerSize)).Slice(0, commandBufferHeader.NumEntries);
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
{
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);
if (map == null)
{
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");
return NvInternalResult.InvalidInput;
}
lock (map)
{
if (map.DmaMapAddress != 0)
{
vmm.Free(map.DmaMapAddress, map.Size);
map.DmaMapAddress = 0;
}
}
}
return NvInternalResult.Success;
}
private NvInternalResult SetNvMapFd(ref int nvMapFd)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult SetTimeout(ref uint timeout)
{
_timeout = timeout;
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult SubmitGpfifo(Span<byte> arguments)
{
int headerSize = Unsafe.SizeOf<SubmitGpfifoArguments>();
SubmitGpfifoArguments gpfifoSubmissionHeader = MemoryMarshal.Cast<byte, SubmitGpfifoArguments>(arguments)[0];
Span<long> gpfifoEntries = MemoryMarshal.Cast<byte, long>(arguments.Slice(headerSize)).Slice(0, gpfifoSubmissionHeader.NumEntries);
return SubmitGpfifo(ref gpfifoSubmissionHeader, gpfifoEntries);
}
private NvInternalResult AllocObjCtx(ref AllocObjCtxArguments arguments)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult ZcullBind(ref ZcullBindArguments arguments)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult SetErrorNotifier(ref SetErrorNotifierArguments arguments)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult SetPriority(ref NvChannelPriority priority)
{
switch (priority)
{
case NvChannelPriority.Low:
_timeslice = 1300; // Timeslice low priority in micro-seconds
break;
case NvChannelPriority.Medium:
_timeslice = 2600; // Timeslice medium priority in micro-seconds
break;
case NvChannelPriority.High:
_timeslice = 5200; // Timeslice high priority in micro-seconds
break;
default:
return NvInternalResult.InvalidInput;
}
Logger.PrintStub(LogClass.ServiceNv);
// TODO: disable and preempt channel when GPU scheduler will be implemented.
return NvInternalResult.Success;
}
private NvInternalResult AllocGpfifoEx(ref AllocGpfifoExArguments arguments)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult AllocGpfifoEx2(ref AllocGpfifoExArguments arguments)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
private NvInternalResult SetTimeslice(ref uint timeslice)
{
if (timeslice < 1000 || timeslice > 50000)
{
return NvInternalResult.InvalidInput;
}
_timeslice = timeslice; // in micro-seconds
Logger.PrintStub(LogClass.ServiceNv);
// TODO: disable and preempt channel when GPU scheduler will be implemented.
return NvInternalResult.Success;
}
private NvInternalResult SetUserData(ref ulong userData)
{
Logger.PrintStub(LogClass.ServiceNv);
return NvInternalResult.Success;
}
protected NvInternalResult SubmitGpfifo(ref SubmitGpfifoArguments header, Span<long> entries)
{
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
foreach (long entry in entries)
{
_gpu.Pusher.Push(vmm, entry);
}
header.Fence.Id = 0;
header.Fence.Value = 0;
return NvInternalResult.Success;
}
public override void Close() { }
}
}

View file

@ -1,371 +0,0 @@
using ARMeilleure.Memory;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using System;
using System.Collections.Concurrent;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
class NvHostChannelIoctl
{
private static ConcurrentDictionary<KProcess, NvChannel> _channels;
static NvHostChannelIoctl()
{
_channels = new ConcurrentDictionary<KProcess, NvChannel>();
}
public static int ProcessIoctl(ServiceCtx context, int cmd)
{
switch (cmd & 0xffff)
{
case 0x0001: return Submit (context);
case 0x0002: return GetSyncpoint (context);
case 0x0003: return GetWaitBase (context);
case 0x0007: return SetSubmitTimeout (context);
case 0x0009: return MapBuffer (context);
case 0x000a: return UnmapBuffer (context);
case 0x4714: return SetUserData (context);
case 0x4801: return SetNvMap (context);
case 0x4803: return SetTimeout (context);
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);
case 0x481d: return SetTimeslice (context);
}
throw new NotImplementedException(cmd.ToString("x8"));
}
private static int Submit(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
NvHostChannelSubmit args = MemoryHelper.Read<NvHostChannelSubmit>(context.Memory, inputPosition);
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
for (int index = 0; index < args.CmdBufsCount; index++)
{
long cmdBufOffset = inputPosition + 0x10 + index * 0xc;
NvHostChannelCmdBuf cmdBuf = MemoryHelper.Read<NvHostChannelCmdBuf>(context.Memory, cmdBufOffset);
NvMapHandle map = NvMapIoctl.GetNvMap(context, cmdBuf.MemoryId);
int[] cmdBufData = new int[cmdBuf.WordsCount];
for (int offset = 0; offset < cmdBufData.Length; offset++)
{
cmdBufData[offset] = context.Memory.ReadInt32(map.Address + cmdBuf.Offset + offset * 4);
}
context.Device.Gpu.PushCommandBuffer(vmm, cmdBufData);
}
// TODO: Relocation, waitchecks, etc.
return NvResult.Success;
}
private static int GetSyncpoint(ServiceCtx context)
{
// TODO
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
NvHostChannelGetParamArg args = MemoryHelper.Read<NvHostChannelGetParamArg>(context.Memory, inputPosition);
args.Value = 0;
MemoryHelper.Write(context.Memory, outputPosition, args);
return NvResult.Success;
}
private static int GetWaitBase(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
NvHostChannelGetParamArg args = MemoryHelper.Read<NvHostChannelGetParamArg>(context.Memory, inputPosition);
args.Value = 0;
MemoryHelper.Write(context.Memory, outputPosition, args);
return NvResult.Success;
}
private static int SetSubmitTimeout(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
GetChannel(context).SubmitTimeout = context.Memory.ReadInt32(inputPosition);
// TODO: Handle the timeout in the submit method.
Logger.PrintStub(LogClass.ServiceNv);
return NvResult.Success;
}
private static int MapBuffer(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
NvHostChannelMapBuffer args = MemoryHelper.Read<NvHostChannelMapBuffer>(context.Memory, inputPosition);
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
for (int index = 0; index < args.NumEntries; index++)
{
int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8);
NvMapHandle map = NvMapIoctl.GetNvMap(context, handle);
if (map == null)
{
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!");
return NvResult.InvalidInput;
}
lock (map)
{
if (map.DmaMapAddress == 0)
{
map.DmaMapAddress = vmm.MapLow(map.Address, map.Size);
}
context.Memory.WriteInt32(outputPosition + 0xc + 4 + index * 8, (int)map.DmaMapAddress);
}
}
return NvResult.Success;
}
private static int UnmapBuffer(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
NvHostChannelMapBuffer args = MemoryHelper.Read<NvHostChannelMapBuffer>(context.Memory, inputPosition);
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
for (int index = 0; index < args.NumEntries; index++)
{
int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8);
NvMapHandle map = NvMapIoctl.GetNvMap(context, handle);
if (map == null)
{
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!");
return NvResult.InvalidInput;
}
lock (map)
{
if (map.DmaMapAddress != 0)
{
vmm.Free(map.DmaMapAddress, map.Size);
map.DmaMapAddress = 0;
}
}
}
return NvResult.Success;
}
private static int SetUserData(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
Logger.PrintStub(LogClass.ServiceNv);
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);
return NvResult.Success;
}
private static int SetTimeout(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
GetChannel(context).Timeout = context.Memory.ReadInt32(inputPosition);
Logger.PrintStub(LogClass.ServiceNv);
return NvResult.Success;
}
private static int SubmitGpfifo(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
NvHostChannelSubmitGpfifo args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(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;
MemoryHelper.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);
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);
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);
return NvResult.Success;
}
private static int SetPriority(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
switch ((NvChannelPriority)context.Memory.ReadInt32(inputPosition))
{
case NvChannelPriority.Low:
GetChannel(context).Timeslice = 1300; // Timeslice low priority in micro-seconds
break;
case NvChannelPriority.Medium:
GetChannel(context).Timeslice = 2600; // Timeslice medium priority in micro-seconds
break;
case NvChannelPriority.High:
GetChannel(context).Timeslice = 5200; // Timeslice high priority in micro-seconds
break;
default:
return NvResult.InvalidInput;
}
Logger.PrintStub(LogClass.ServiceNv);
// TODO: disable and preempt channel when GPU scheduler will be implemented.
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);
return NvResult.Success;
}
private static int KickoffPbWithAttr(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
long outputPosition = context.Request.GetBufferType0x22().Position;
NvHostChannelSubmitGpfifo args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(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;
MemoryHelper.Write(context.Memory, outputPosition, args);
return NvResult.Success;
}
private static int SetTimeslice(ServiceCtx context)
{
long inputPosition = context.Request.GetBufferType0x21().Position;
int timeslice = context.Memory.ReadInt32(inputPosition);
if (timeslice < 1000 || timeslice > 50000)
{
return NvResult.InvalidInput;
}
GetChannel(context).Timeslice = timeslice; // in micro-seconds
Logger.PrintStub(LogClass.ServiceNv);
// TODO: disable and preempt channel when GPU scheduler will be implemented.
return NvResult.Success;
}
private static void PushGpfifo(ServiceCtx context, NvGpuVmm vmm, long gpfifo)
{
context.Device.Gpu.Pusher.Push(vmm, gpfifo);
}
public static NvChannel GetChannel(ServiceCtx context)
{
return _channels.GetOrAdd(context.Process, (key) => new NvChannel());
}
public static void UnloadProcess(KProcess process)
{
_channels.TryRemove(process, out _);
}
}
}

View file

@ -0,0 +1,78 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
using System;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
internal class NvHostGpuDeviceFile : NvHostChannelDeviceFile
{
private KEvent _smExceptionBptIntReportEvent;
private KEvent _smExceptionBptPauseReportEvent;
private KEvent _errorNotifierEvent;
public NvHostGpuDeviceFile(ServiceCtx context) : base(context)
{
_smExceptionBptIntReportEvent = new KEvent(context.Device.System);
_smExceptionBptPauseReportEvent = new KEvent(context.Device.System);
_errorNotifierEvent = new KEvent(context.Device.System);
}
public override NvInternalResult Ioctl2(NvIoctl command, Span<byte> arguments, Span<byte> inlineInBuffer)
{
NvInternalResult result = NvInternalResult.NotImplemented;
if (command.Type == NvIoctl.NvHostMagic)
{
switch (command.Number)
{
case 0x1b:
result = CallIoctlMethod<SubmitGpfifoArguments, long>(SubmitGpfifoEx, arguments, inlineInBuffer);
break;
}
}
return result;
}
public override NvInternalResult QueryEvent(out int eventHandle, uint eventId)
{
// TODO: accurately represent and implement those events.
KEvent targetEvent = null;
switch (eventId)
{
case 0x1:
targetEvent = _smExceptionBptIntReportEvent;
break;
case 0x2:
targetEvent = _smExceptionBptPauseReportEvent;
break;
case 0x3:
targetEvent = _errorNotifierEvent;
break;
}
if (targetEvent != null)
{
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
else
{
eventHandle = 0;
return NvInternalResult.InvalidInput;
}
return NvInternalResult.Success;
}
private NvInternalResult SubmitGpfifoEx(ref SubmitGpfifoArguments arguments, Span<long> inlineData)
{
return SubmitGpfifo(ref arguments, inlineData);
}
}
}

View file

@ -0,0 +1,17 @@
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct AllocGpfifoExArguments
{
public uint NumEntries;
public uint NumJobs;
public uint Flags;
public NvFence Fence;
public uint Reserved1;
public uint Reserved2;
public uint Reserved3;
}
}

View file

@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct AllocObjCtxArguments
{
public uint ClassNumber;
public uint Flags;
public ulong ObjectId;
}
}

View file

@ -0,0 +1,11 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct GetParameterArguments
{
public uint Parameter;
public uint Value;
}
}

View file

@ -0,0 +1,21 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct CommandBufferHandle
{
public int MapHandle;
public int MapAddress;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MapCommandBufferArguments
{
public int NumEntries;
public int DataAddress; // Ignored by the driver.
public bool AttachHostChDas;
public byte Padding1;
public short Padding2;
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
enum NvChannelPriority
enum NvChannelPriority : uint
{
Low = 50,
Medium = 100,

View file

@ -1,12 +0,0 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
struct NvHostChannelCmdBuf
{
public int MemoryId;
public int Offset;
public int WordsCount;
}
}

View file

@ -1,11 +0,0 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
struct NvHostChannelGetParamArg
{
public int Param;
public int Value;
}
}

View file

@ -1,12 +0,0 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
[StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 4)]
struct NvHostChannelMapBuffer
{
public int NumEntries;
public int DataAddress; // Ignored by the driver.
public bool AttachHostChDas;
}
}

View file

@ -1,13 +0,0 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
struct NvHostChannelSubmit
{
public int CmdBufsCount;
public int RelocsCount;
public int SyncptIncrsCount;
public int WaitchecksCount;
}
}

View file

@ -1,11 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
{
struct NvHostChannelSubmitGpfifo
{
public long Address;
public int NumEntries;
public int Flags;
public int SyncptId;
public int SyncptValue;
}
}

View file

@ -0,0 +1,13 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct SetErrorNotifierArguments
{
public ulong Offset;
public ulong Size;
public uint Mem;
public uint Reserved;
}
}

View file

@ -0,0 +1,21 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct CommandBuffer
{
public int MemoryId;
public int Offset;
public int WordsCount;
}
[StructLayout(LayoutKind.Sequential)]
struct SubmitArguments
{
public int CmdBufsCount;
public int RelocsCount;
public int SyncptIncrsCount;
public int WaitchecksCount;
}
}

View file

@ -0,0 +1,14 @@
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct SubmitGpfifoArguments
{
public long Address;
public int NumEntries;
public int Flags;
public NvFence Fence;
}
}

View file

@ -0,0 +1,12 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
{
[StructLayout(LayoutKind.Sequential)]
struct ZcullBindArguments
{
public ulong GpuVirtualAddress;
public uint Mode;
public uint Reserved;
}
}