diff --git a/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs index 5580c3be4e..fec9d7d0b6 100644 --- a/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/Android/NvFlinger.cs @@ -2,7 +2,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using System; using System.Collections.Generic; @@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Android int bufferOffset = _bufferQueue[slot].Data.Buffer.Surfaces[0].Offset; - NvMapHandle map = NvMapIoctl.GetNvMap(context, nvMapHandle); + NvMapHandle map = NvMapFileDevice.GetMapFromHandle(context.Process, nvMapHandle); long fbAddr = map.Address + bufferOffset; @@ -312,7 +312,7 @@ namespace Ryujinx.HLE.HOS.Services.Android int right = crop.Right; int bottom = crop.Bottom; - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(context.Process).Vmm; _renderer.QueueAction(() => { diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index da34421b74..b19549abc7 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -1,104 +1,296 @@ using ARMeilleure.Memory; +using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS; -using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu; -using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; +using Ryujinx.HLE.HOS.Services.Nv.Types; using System; using System.Collections.Generic; +using System.Reflection; namespace Ryujinx.HLE.HOS.Services.Nv { [Service("nvdrv")] [Service("nvdrv:a")] + [Service("nvdrv:s")] + [Service("nvdrv:t")] class INvDrvServices : IpcService { - private delegate int IoctlProcessor(ServiceCtx context, int cmd); - - private static Dictionary _ioctlProcessors = - new Dictionary() + // TODO: everything + private static Dictionary _fileDeviceRegistry = + new Dictionary() { - { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS }, - { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl }, - { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu }, - { "/dev/nvhost-gpu", ProcessIoctlNvHostChannel }, - { "/dev/nvhost-nvdec", ProcessIoctlNvHostChannel }, - { "/dev/nvhost-vic", ProcessIoctlNvHostChannel }, - { "/dev/nvmap", ProcessIoctlNvMap } + { "/dev/nvhost-as-gpu", typeof(NvHostAsGpuFileDevice) }, + { "/dev/nvhost-ctrl", typeof(NvHostCtrlFileDevice) }, + { "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuFileDevice) }, + //{ "/dev/nvhost-gpu", typeof(NvMapFileDevice) }, + //{ "/dev/nvhost-nvdec", typeof(NvMapFileDevice) }, + //{ "/dev/nvhost-vic", typeof(NvMapFileDevice) }, + { "/dev/nvmap", typeof(NvMapFileDevice) } }; - public static GlobalStateTable Fds { get; private set; } - - private KEvent _event; + private static IdDictionary _fileDeviceIdRegistry = new IdDictionary(); + private KProcess _owner; public INvDrvServices(ServiceCtx context) { - _event = new KEvent(context.Device.System); + _owner = null; } static INvDrvServices() { - Fds = new GlobalStateTable(); + // TODO: dynamically generate _channelRegistry with attribute + } + + private int Open(string path) + { + if (_fileDeviceRegistry.TryGetValue(path, out Type fileDeviceClass)) + { + ConstructorInfo constructor = fileDeviceClass.GetConstructor(new Type[] { typeof(KProcess) }); + + NvFileDevice fileDevice = (NvFileDevice)constructor.Invoke(new object[] { _owner }); + + return _fileDeviceIdRegistry.Add(fileDevice); + } + + Logger.PrintWarning(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!"); + + return -1; + } + + private NvResult GetIoctlArgument(ServiceCtx context, NvIoctl ioctlCommand, out Span arguments) + { + (long inputDataPosition, long inputDataSize) = context.Request.GetBufferType0x21(0); + (long outputDataPosition, long outputDataSize) = context.Request.GetBufferType0x22(0); + + NvIoctl.Direction ioctlDirection = ioctlCommand.GetDirectionValue(); + uint ioctlSize = ioctlCommand.GetSizeValue(); + + bool isRead = (ioctlDirection & NvIoctl.Direction.Read) == NvIoctl.Direction.Read; + bool isWrite = (ioctlDirection & NvIoctl.Direction.Write) == NvIoctl.Direction.Write; + + if ((isWrite && ioctlSize > outputDataSize) || (isRead && ioctlSize > inputDataSize)) + { + arguments = null; + + Logger.PrintWarning(LogClass.ServiceNv, "Ioctl size inconsistency found!"); + + return NvResult.InvalidSize; + } + + if (isRead && isWrite) + { + if (outputDataPosition < inputDataSize) + { + arguments = null; + + Logger.PrintWarning(LogClass.ServiceNv, "Ioctl size inconsistency found!"); + + return NvResult.InvalidSize; + } + + byte[] outputData = new byte[outputDataSize]; + + context.Memory.ReadBytes(inputDataPosition, outputData, 0, (int)inputDataSize); + + arguments = new Span(outputData); + } + else if (isWrite) + { + byte[] outputData = new byte[outputDataSize]; + + arguments = new Span(outputData); + } + else + { + arguments = new Span(context.Memory.ReadBytes(inputDataPosition, inputDataSize)); + } + + return NvResult.Success; + } + + private NvResult GetFileDeviceFromFd(int fd, out NvFileDevice fileDevice) + { + fileDevice = null; + + if (fd < 0) + { + return NvResult.InvalidParameter; + } + + fileDevice = _fileDeviceIdRegistry.GetData(fd); + + if (fileDevice == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid file descriptor {fd}"); + + return NvResult.NotImplemented; + } + + if (fileDevice.GetOwner().Pid != _owner.Pid) + { + return NvResult.AccessDenied; + } + + return NvResult.Success; + } + + private NvResult EnsureInitialized() + { + if (_owner == null) + { + Logger.PrintWarning(LogClass.ServiceNv, "INvDrvServices is not initialized!"); + + return NvResult.NotInitialized; + } + + return NvResult.Success; + } + + private static NvResult ConvertInternalErrorCode(NvInternalResult errorCode) + { + switch (errorCode) + { + case NvInternalResult.Success: + return NvResult.Success; + case NvInternalResult.Unknown0x72: + return NvResult.AlreadyAllocated; + case NvInternalResult.TimedOut: + case NvInternalResult.TryAgain: + case NvInternalResult.Interrupted: + return NvResult.Timeout; + case NvInternalResult.InvalidAddress: + return NvResult.InvalidAddress; + case NvInternalResult.NotSupported: + case NvInternalResult.Unknown0x18: + return NvResult.NotSupported; + case NvInternalResult.InvalidState: + return NvResult.InvalidState; + case NvInternalResult.ReadOnlyAttribute: + return NvResult.ReadOnlyAttribute; + case NvInternalResult.NoSpaceLeft: + case NvInternalResult.FileTooBig: + return NvResult.InvalidSize; + case NvInternalResult.FileTableOverflow: + case NvInternalResult.BadFileNumber: + return NvResult.FileOperationFailed; + case NvInternalResult.InvalidInput: + return NvResult.InvalidValue; + case NvInternalResult.NotADirectory: + return NvResult.DirectoryOperationFailed; + case NvInternalResult.Busy: + return NvResult.Busy; + case NvInternalResult.BadAddress: + return NvResult.InvalidAddress; + case NvInternalResult.AccessDenied: + case NvInternalResult.OperationNotPermitted: + return NvResult.AccessDenied; + case NvInternalResult.OutOfMemory: + return NvResult.InsufficientMemory; + case NvInternalResult.DeviceNotFound: + return NvResult.ModuleNotPresent; + case NvInternalResult.IoError: + return NvResult.ResourceError; + default: + return NvResult.IoctlFailed; + } } [Command(0)] - // Open(buffer path) -> (u32 fd, u32 error_code) + // Open(buffer path) -> (s32 fd, u32 error_code) public ResultCode Open(ServiceCtx context) { - long namePtr = context.Request.SendBuff[0].Position; + NvResult errorCode = EnsureInitialized(); + int fd = -1; - string name = MemoryHelper.ReadAsciiString(context.Memory, namePtr); + if (errorCode == NvResult.Success) + { + long pathPtr = context.Request.SendBuff[0].Position; - int fd = Fds.Add(context.Process, new NvFd(name)); + string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr); + + fd = Open(path); + + if (fd == -1) + { + errorCode = NvResult.FileOperationFailed; + } + } context.ResponseData.Write(fd); - context.ResponseData.Write(0); + context.ResponseData.Write((uint)errorCode); return ResultCode.Success; } [Command(1)] - // Ioctl(u32 fd, u32 rq_id, buffer) -> (u32 error_code, buffer) - [Command(11)] // 3.0.0+ - // Ioctl2(u32, u32, buffer, buffer) -> (u32, buffer) + // Ioctl(s32 fd, u32 ioctl_cmd, buffer in_args) -> (u32 error_code, buffer out_args) public ResultCode Ioctl(ServiceCtx context) { - int fd = context.RequestData.ReadInt32(); - int cmd = context.RequestData.ReadInt32(); + NvResult errorCode = EnsureInitialized(); - NvFd fdData = Fds.GetData(context.Process, fd); - - int result = 0; - - if (_ioctlProcessors.TryGetValue(fdData.Name, out IoctlProcessor process)) + if (errorCode == NvResult.Success) { - result = process(context, cmd); - } - else if (!ServiceConfiguration.IgnoreMissingServices) - { - throw new NotImplementedException($"{fdData.Name} {cmd:x4}"); + int fd = context.RequestData.ReadInt32(); + NvIoctl ioctlCommand = context.RequestData.ReadStruct(); + + errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); + + if (errorCode == NvResult.Success) + { + errorCode = GetFileDeviceFromFd(fd, out NvFileDevice fileDevice); + + if (errorCode == NvResult.Success) + { + NvInternalResult internalResult = fileDevice.Ioctl(ioctlCommand, arguments); + + if (internalResult == NvInternalResult.NotImplemented) + { + throw new NvIoctlNotImplementedException(context, fileDevice, ioctlCommand); + } + + errorCode = ConvertInternalErrorCode(internalResult); + + if (errorCode == NvResult.Success && (ioctlCommand.GetDirectionValue() & NvIoctl.Direction.Write) == NvIoctl.Direction.Write) + { + context.Memory.WriteBytes(context.Request.GetBufferType0x22(0).Position, arguments.ToArray()); + } + } + } } - // TODO: Verify if the error codes needs to be translated. - context.ResponseData.Write(result); + context.ResponseData.Write((uint)errorCode); return ResultCode.Success; } [Command(2)] - // Close(u32 fd) -> u32 error_code + // Close(s32 fd) -> u32 error_code public ResultCode Close(ServiceCtx context) { - int fd = context.RequestData.ReadInt32(); + NvResult errorCode = EnsureInitialized(); - Fds.Delete(context.Process, fd); + if (errorCode == NvResult.Success) + { + int fd = context.RequestData.ReadInt32(); - context.ResponseData.Write(0); + errorCode = GetFileDeviceFromFd(fd, out NvFileDevice fileDevice); + + if (errorCode == NvResult.Success) + { + fileDevice.Close(); + } + } + + context.ResponseData.Write((uint)errorCode); return ResultCode.Success; } @@ -110,127 +302,123 @@ namespace Ryujinx.HLE.HOS.Services.Nv long transferMemSize = context.RequestData.ReadInt64(); int transferMemHandle = context.Request.HandleDesc.ToCopy[0]; - NvMapIoctl.InitializeNvMap(context); + _owner = context.Process; - context.ResponseData.Write(0); + context.ResponseData.Write((uint)NvResult.Success); return ResultCode.Success; } [Command(4)] - // QueryEvent(u32 fd, u32 event_id) -> (u32, handle) + // QueryEvent(s32 fd, u32 event_id) -> (u32, handle) public ResultCode QueryEvent(ServiceCtx context) { - int fd = context.RequestData.ReadInt32(); - int eventId = context.RequestData.ReadInt32(); + NvResult errorCode = EnsureInitialized(); - // TODO: Use Fd/EventId, different channels have different events. - if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success) + if (errorCode == NvResult.Success) { - throw new InvalidOperationException("Out of handles!"); + int fd = context.RequestData.ReadInt32(); + uint eventId = context.RequestData.ReadUInt32(); + + errorCode = GetFileDeviceFromFd(fd, out NvFileDevice fileDevice); + + if (errorCode == NvResult.Success) + { + errorCode = ConvertInternalErrorCode(fileDevice.QueryEvent(out int eventHandle, eventId)); + + if (errorCode == NvResult.Success) + { + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(eventHandle); + } + } } - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); - - context.ResponseData.Write(0); + context.ResponseData.Write((uint)errorCode); return ResultCode.Success; } + [Command(5)] + // MapSharedMemory(s32 fd, u32 argument, handle) -> u32 error_code + public ResultCode MapSharedMemory(ServiceCtx context) + { + NvResult errorCode = EnsureInitialized(); + + if (errorCode == NvResult.Success) + { + int fd = context.RequestData.ReadInt32(); + uint argument = context.RequestData.ReadUInt32(); + int sharedMemoryHandle = context.Request.HandleDesc.ToCopy[0]; + + errorCode = GetFileDeviceFromFd(fd, out NvFileDevice fileDevice); + + if (errorCode == NvResult.Success) + { + KSharedMemory sharedMemory = context.Process.HandleTable.GetObject(sharedMemoryHandle); + + errorCode = ConvertInternalErrorCode(fileDevice.MapSharedMemory(sharedMemory, argument)); + } + } + + context.ResponseData.Write((uint)errorCode); + + return ResultCode.Success; + } + + [Command(6)] + // GetStatus() -> (unknown<0x20>, u32 error_code) + public ResultCode GetStatus(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(7)] + // ForceSetClientPid(u64) -> u32 error_code + public ResultCode ForceSetClientPid(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + [Command(8)] // SetClientPID(u64, pid) -> u32 error_code public ResultCode SetClientPid(ServiceCtx context) { - long pid = context.RequestData.ReadInt64(); - - context.ResponseData.Write(0); - - return ResultCode.Success; + throw new ServiceNotImplementedException(context); } [Command(9)] // DumpGraphicsMemoryInfo() public ResultCode DumpGraphicsMemoryInfo(ServiceCtx context) { - Logger.PrintStub(LogClass.ServiceNv); - - return ResultCode.Success; + throw new ServiceNotImplementedException(context); } - [Command(13)] + [Command(10)] // 3.0.0+ + // InitializeDevtools(u32, handle) -> u32 error_code; + public ResultCode InitializeDevtools(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(11)] // 3.0.0+ + // Ioctl2(s32 fd, u32 ioctl_cmd, buffer in_args, buffer in_additional_buffer) -> (u32 error_code, buffer out_args) + public ResultCode Ioctl2(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(12)] // 3.0.0+ + // Ioctl2(s32 fd, u32 ioctl_cmd, buffer in_args) -> (u32 error_code, buffer out_args, buffer out_additional_buffer) + public ResultCode Ioctl3(ServiceCtx context) + { + throw new ServiceNotImplementedException(context); + } + + [Command(13)] // 3.0.0+ // FinishInitialize(unknown<8>) public ResultCode FinishInitialize(ServiceCtx context) { - Logger.PrintStub(LogClass.ServiceNv); - - return ResultCode.Success; - } - - private static int ProcessIoctlNvGpuAS(ServiceCtx context, int cmd) - { - return ProcessIoctl(context, cmd, NvGpuASIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvHostCtrl(ServiceCtx context, int cmd) - { - return ProcessIoctl(context, cmd, NvHostCtrlIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvGpuGpu(ServiceCtx context, int cmd) - { - return ProcessIoctl(context, cmd, NvGpuGpuIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvHostChannel(ServiceCtx context, int cmd) - { - return ProcessIoctl(context, cmd, NvHostChannelIoctl.ProcessIoctl); - } - - private static int ProcessIoctlNvMap(ServiceCtx context, int cmd) - { - return ProcessIoctl(context, cmd, NvMapIoctl.ProcessIoctl); - } - - private static int ProcessIoctl(ServiceCtx context, int cmd, IoctlProcessor processor) - { - if (CmdIn(cmd) && context.Request.GetBufferType0x21().Position == 0) - { - Logger.PrintError(LogClass.ServiceNv, "Input buffer is null!"); - - return NvResult.InvalidInput; - } - - if (CmdOut(cmd) && context.Request.GetBufferType0x22().Position == 0) - { - Logger.PrintError(LogClass.ServiceNv, "Output buffer is null!"); - - return NvResult.InvalidInput; - } - - return processor(context, cmd); - } - - private static bool CmdIn(int cmd) - { - return ((cmd >> 30) & 1) != 0; - } - - private static bool CmdOut(int cmd) - { - return ((cmd >> 31) & 1) != 0; - } - - public static void UnloadProcess(KProcess process) - { - Fds.DeleteProcess(process); - - NvGpuASIoctl.UnloadProcess(process); - - NvHostChannelIoctl.UnloadProcess(process); - - NvHostCtrlIoctl.UnloadProcess(process); - - NvMapIoctl.UnloadProcess(process); + throw new ServiceNotImplementedException(context); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceAttribute.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceAttribute.cs new file mode 100644 index 0000000000..fadf6fe6bf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvDeviceAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices +{ + class NvDeviceAttribute : Attribute + { + public readonly string Path; + + public NvDeviceAttribute(string path) => Path = path; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs new file mode 100644 index 0000000000..2bb33be00d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs @@ -0,0 +1,71 @@ +using Ryujinx.HLE.HOS.Kernel.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices +{ + abstract class NvFileDevice : IDisposable + { + protected KProcess _owner; + + public NvFileDevice(KProcess owner) + { + _owner = owner; + } + + public KProcess GetOwner() + { + return _owner; + } + + public virtual NvInternalResult QueryEvent(out int eventHandle, uint eventId) + { + eventHandle = 0; + + return NvInternalResult.NotImplemented; + } + + public virtual NvInternalResult MapSharedMemory(KSharedMemory sharedMemory, uint argument) + { + return NvInternalResult.NotImplemented; + } + + public virtual NvInternalResult Ioctl(NvIoctl command, Span arguments) + { + return NvInternalResult.NotImplemented; + } + + public virtual NvInternalResult Ioctl2(NvIoctl command, Span arguments, Span inBuffer) + { + return NvInternalResult.NotImplemented; + } + + public virtual NvInternalResult Ioctl3(NvIoctl command, Span arguments, Span outBuffer) + { + return NvInternalResult.NotImplemented; + } + + protected delegate NvInternalResult IoctlProcessor(ref T arguments); + protected delegate NvInternalResult IoctlProcessorSpan(Span arguments); + + protected static NvInternalResult CallIoctlMethod(IoctlProcessor callback, Span arguments) where T : struct + { + Debug.Assert(arguments.Length == Marshal.SizeOf()); + return callback(ref MemoryMarshal.Cast(arguments)[0]); + } + + protected static NvInternalResult CallIoctlMethod(IoctlProcessorSpan callback, Span arguments) where T : struct + { + return callback(MemoryMarshal.Cast(arguments)); + } + + public abstract void Close(); + + public void Dispose() + { + Close(); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs deleted file mode 100644 index 5c8d1fe0d6..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/NvGpuASIoctl.cs +++ /dev/null @@ -1,330 +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.NvMap; -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS -{ - class NvGpuASIoctl - { - private const int FlagFixedOffset = 1; - - private const int FlagRemapSubRange = 0x100; - - private static ConcurrentDictionary _asCtxs; - - static NvGpuASIoctl() - { - _asCtxs = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x4101: return BindChannel (context); - case 0x4102: return AllocSpace (context); - case 0x4103: return FreeSpace (context); - case 0x4105: return UnmapBuffer (context); - case 0x4106: return MapBufferEx (context); - case 0x4108: return GetVaRegions(context); - case 0x4109: return InitializeEx(context); - case 0x4114: return Remap (context, cmd); - } - - throw new NotImplementedException(cmd.ToString("x8")); - } - - private static int BindChannel(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int AllocSpace(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASAllocSpace args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - ulong size = (ulong)args.Pages * - (ulong)args.PageSize; - - int result = NvResult.Success; - - lock (asCtx) - { - // Note: When the fixed offset flag is not set, - // the Offset field holds the alignment size instead. - if ((args.Flags & FlagFixedOffset) != 0) - { - args.Offset = asCtx.Vmm.ReserveFixed(args.Offset, (long)size); - } - else - { - args.Offset = asCtx.Vmm.Reserve((long)size, args.Offset); - } - - if (args.Offset < 0) - { - args.Offset = 0; - - Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!"); - - result = NvResult.OutOfMemory; - } - else - { - asCtx.AddReservation(args.Offset, (long)size); - } - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return result; - } - - private static int FreeSpace(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASAllocSpace args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - int result = NvResult.Success; - - lock (asCtx) - { - ulong size = (ulong)args.Pages * - (ulong)args.PageSize; - - if (asCtx.RemoveReservation(args.Offset)) - { - asCtx.Vmm.Free(args.Offset, (long)size); - } - else - { - Logger.PrintWarning(LogClass.ServiceNv, - $"Failed to free offset 0x{args.Offset:x16} size 0x{size:x16}!"); - - result = NvResult.InvalidInput; - } - } - - return result; - } - - private static int UnmapBuffer(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASUnmapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - lock (asCtx) - { - if (asCtx.RemoveMap(args.Offset, out long size)) - { - if (size != 0) - { - asCtx.Vmm.Free(args.Offset, size); - } - } - else - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {args.Offset:x16}!"); - } - } - - return NvResult.Success; - } - - private static int MapBufferEx(ServiceCtx context) - { - const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; - - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuASMapBufferEx args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuASCtx asCtx = GetASCtx(context); - - NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); - - return NvResult.InvalidInput; - } - - long pa; - - if ((args.Flags & FlagRemapSubRange) != 0) - { - lock (asCtx) - { - if (asCtx.TryGetMapPhysicalAddress(args.Offset, out pa)) - { - long va = args.Offset + args.BufferOffset; - - pa += args.BufferOffset; - - if (asCtx.Vmm.Map(pa, va, args.MappingSize) < 0) - { - string msg = string.Format(mapErrorMsg, va, args.MappingSize); - - Logger.PrintWarning(LogClass.ServiceNv, msg); - - return NvResult.InvalidInput; - } - - return NvResult.Success; - } - else - { - Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{args.Offset:x16} not mapped!"); - - return NvResult.InvalidInput; - } - } - } - - pa = map.Address + args.BufferOffset; - - long size = args.MappingSize; - - if (size == 0) - { - size = (uint)map.Size; - } - - int result = NvResult.Success; - - lock (asCtx) - { - // Note: When the fixed offset flag is not set, - // the Offset field holds the alignment size instead. - bool vaAllocated = (args.Flags & FlagFixedOffset) == 0; - - if (!vaAllocated) - { - if (asCtx.ValidateFixedBuffer(args.Offset, size)) - { - args.Offset = asCtx.Vmm.Map(pa, args.Offset, size); - } - else - { - string msg = string.Format(mapErrorMsg, args.Offset, size); - - Logger.PrintWarning(LogClass.ServiceNv, msg); - - result = NvResult.InvalidInput; - } - } - else - { - args.Offset = asCtx.Vmm.Map(pa, size); - } - - if (args.Offset < 0) - { - args.Offset = 0; - - Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); - - result = NvResult.InvalidInput; - } - else - { - asCtx.AddMap(args.Offset, size, pa, vaAllocated); - } - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return result; - } - - private static int GetVaRegions(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int InitializeEx(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int Remap(ServiceCtx context, int cmd) - { - int count = ((cmd >> 16) & 0xff) / 0x14; - - long inputPosition = context.Request.GetBufferType0x21().Position; - - for (int index = 0; index < count; index++, inputPosition += 0x14) - { - NvGpuASRemap args = MemoryHelper.Read(context.Memory, inputPosition); - - NvGpuVmm vmm = GetASCtx(context).Vmm; - - NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); - - return NvResult.InvalidInput; - } - - long result = vmm.Map(map.Address, (long)(uint)args.Offset << 16, - (long)(uint)args.Pages << 16); - - if (result < 0) - { - Logger.PrintWarning(LogClass.ServiceNv, - $"Page 0x{args.Offset:x16} size 0x{args.Pages:x16} not allocated!"); - - return NvResult.InvalidInput; - } - } - - return NvResult.Success; - } - - public static NvGpuASCtx GetASCtx(ServiceCtx context) - { - return _asCtxs.GetOrAdd(context.Process, (key) => new NvGpuASCtx(context)); - } - - public static void UnloadProcess(KProcess process) - { - _asCtxs.TryRemove(process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs deleted file mode 100644 index f0a0db35e7..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASAllocSpace.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS -{ - struct NvGpuASAllocSpace - { - public int Pages; - public int PageSize; - public int Flags; - public int Padding; - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs deleted file mode 100644 index 0a6f8003ea..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASRemap.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS -{ - struct NvGpuASRemap - { - public short Flags; - public short Kind; - public int NvMapHandle; - public int Padding; - public int Offset; - public int Pages; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs deleted file mode 100644 index 63476b2fe1..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASUnmapBuffer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS -{ - struct NvGpuASUnmapBuffer - { - public long Offset; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs deleted file mode 100644 index 12f131539a..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/NvGpuGpuIoctl.cs +++ /dev/null @@ -1,190 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common.Logging; -using System; -using System.Diagnostics; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu -{ - class NvGpuGpuIoctl - { - private static Stopwatch _pTimer; - - private static double _ticksToNs; - - static NvGpuGpuIoctl() - { - _pTimer = new Stopwatch(); - - _pTimer.Start(); - - _ticksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x4701: return ZcullGetCtxSize (context); - case 0x4702: return ZcullGetInfo (context); - case 0x4703: return ZbcSetTable (context); - case 0x4705: return GetCharacteristics(context); - case 0x4706: return GetTpcMasks (context); - case 0x4714: return GetActiveSlotMask (context); - case 0x471c: return GetGpuTime (context); - } - - throw new NotImplementedException(cmd.ToString("x8")); - } - - private static int ZcullGetCtxSize(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuZcullGetCtxSize args = new NvGpuGpuZcullGetCtxSize - { - Size = 1 - }; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int ZcullGetInfo(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuZcullGetInfo args = new NvGpuGpuZcullGetInfo - { - WidthAlignPixels = 0x20, - HeightAlignPixels = 0x20, - PixelSquaresByAliquots = 0x400, - AliquotTotal = 0x800, - RegionByteMultiplier = 0x20, - RegionHeaderSize = 0x20, - SubregionHeaderSize = 0xc0, - SubregionWidthAlignPixels = 0x20, - SubregionHeightAlignPixels = 0x40, - SubregionCount = 0x10 - }; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int ZbcSetTable(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int GetCharacteristics(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetCharacteristics args = MemoryHelper.Read(context.Memory, inputPosition); - - args.BufferSize = 0xa0; - - args.Arch = 0x120; - args.Impl = 0xb; - args.Rev = 0xa1; - args.NumGpc = 0x1; - args.L2CacheSize = 0x40000; - args.OnBoardVideoMemorySize = 0x0; - args.NumTpcPerGpc = 0x2; - args.BusType = 0x20; - args.BigPageSize = 0x20000; - args.CompressionPageSize = 0x20000; - args.PdeCoverageBitCount = 0x1b; - args.AvailableBigPageSizes = 0x30000; - args.GpcMask = 0x1; - args.SmArchSmVersion = 0x503; - args.SmArchSpaVersion = 0x503; - args.SmArchWarpCount = 0x80; - args.GpuVaBitCount = 0x28; - args.Reserved = 0x0; - args.Flags = 0x55; - args.TwodClass = 0x902d; - args.ThreedClass = 0xb197; - args.ComputeClass = 0xb1c0; - args.GpfifoClass = 0xb06f; - args.InlineToMemoryClass = 0xa140; - args.DmaCopyClass = 0xb0b5; - args.MaxFbpsCount = 0x1; - args.FbpEnMask = 0x0; - args.MaxLtcPerFbp = 0x2; - args.MaxLtsPerLtc = 0x1; - args.MaxTexPerTpc = 0x0; - args.MaxGpcCount = 0x1; - args.RopL2EnMask0 = 0x21d70; - args.RopL2EnMask1 = 0x0; - args.ChipName = 0x6230326d67; - args.GrCompbitStoreBaseHw = 0x0; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetTpcMasks(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetTpcMasks args = MemoryHelper.Read(context.Memory, inputPosition); - - if (args.MaskBufferSize != 0) - { - args.TpcMask = 3; - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetActiveSlotMask(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvGpuGpuGetActiveSlotMask args = new NvGpuGpuGetActiveSlotMask - { - Slot = 0x07, - Mask = 0x01 - }; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - Logger.PrintStub(LogClass.ServiceNv); - - return NvResult.Success; - } - - private static int GetGpuTime(ServiceCtx context) - { - long outputPosition = context.Request.GetBufferType0x22().Position; - - context.Memory.WriteInt64(outputPosition, GetPTimerNanoSeconds()); - - return NvResult.Success; - } - - private static long GetPTimerNanoSeconds() - { - double ticks = _pTimer.ElapsedTicks; - - return (long)(ticks * _ticksToNs) & 0xff_ffff_ffff_ffff; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs deleted file mode 100644 index 1b4c53451f..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetActiveSlotMask.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu -{ - struct NvGpuGpuGetActiveSlotMask - { - public int Slot; - public int Mask; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs deleted file mode 100644 index bc0966da18..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetTpcMasks.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu -{ - struct NvGpuGpuGetTpcMasks - { - public int MaskBufferSize; - public int Reserved; - public long MaskBufferAddress; - public int TpcMask; - public int Padding; - } -} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs deleted file mode 100644 index 8706d51dae..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetCtxSize.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu -{ - struct NvGpuGpuZcullGetCtxSize - { - public int Size; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuFileDevice.cs new file mode 100644 index 0000000000..cb80d01474 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuFileDevice.cs @@ -0,0 +1,305 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu +{ + class NvHostAsGpuFileDevice : NvFileDevice + { + private const int FlagFixedOffset = 1; + private const int FlagRemapSubRange = 0x100; + + private static ConcurrentDictionary _addressSpaceContextRegistry = new ConcurrentDictionary(); + + public NvHostAsGpuFileDevice(KProcess owner) : base(owner) + { + + } + + public override NvInternalResult Ioctl(NvIoctl command, Span arguments) + { + NvInternalResult result = NvInternalResult.NotImplemented; + + switch (command.GetNumberValue()) + { + case 0x1: + result = CallIoctlMethod(BindChannel, arguments); + break; + case 0x2: + result = CallIoctlMethod(AllocSpace, arguments); + break; + case 0x3: + result = CallIoctlMethod(FreeSpace, arguments); + break; + case 0x5: + result = CallIoctlMethod(UnmapBuffer, arguments); + break; + case 0x6: + result = CallIoctlMethod(MapBufferEx, arguments); + break; + case 0x8: + result = CallIoctlMethod(GetVaRegions, arguments); + break; + case 0x9: + result = CallIoctlMethod(InitializeEx, arguments); + break; + case 0x14: + result = CallIoctlMethod(Remap, arguments); + break; + } + return result; + } + + private NvInternalResult BindChannel(ref BindChannelArguments arguments) + { + Logger.PrintStub(LogClass.ServiceNv); + + return NvInternalResult.Success; + } + + private NvInternalResult AllocSpace(ref AllocSpaceArguments arguments) + { + AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(_owner); + + ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize; + + NvInternalResult result = NvInternalResult.Success; + + lock (addressSpaceContext) + { + // Note: When the fixed offset flag is not set, + // the Offset field holds the alignment size instead. + if ((arguments.Flags & FlagFixedOffset) != 0) + { + arguments.Offset = addressSpaceContext.Vmm.ReserveFixed(arguments.Offset, (long)size); + } + else + { + arguments.Offset = addressSpaceContext.Vmm.Reserve((long)size, arguments.Offset); + } + + if (arguments.Offset < 0) + { + arguments.Offset = 0; + + Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!"); + + result = NvInternalResult.OutOfMemory; + } + else + { + addressSpaceContext.AddReservation(arguments.Offset, (long)size); + } + } + + return result; + } + + private NvInternalResult FreeSpace(ref FreeSpaceArguments arguments) + { + AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(_owner); + + NvInternalResult result = NvInternalResult.Success; + + lock (addressSpaceContext) + { + ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize; + + if (addressSpaceContext.RemoveReservation(arguments.Offset)) + { + addressSpaceContext.Vmm.Free(arguments.Offset, (long)size); + } + else + { + Logger.PrintWarning(LogClass.ServiceNv, + $"Failed to free offset 0x{arguments.Offset:x16} size 0x{size:x16}!"); + + result = NvInternalResult.InvalidInput; + } + } + + return result; + } + + private NvInternalResult UnmapBuffer(ref UnmapBufferArguments arguments) + { + AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(_owner); + + lock (addressSpaceContext) + { + if (addressSpaceContext.RemoveMap(arguments.Offset, out long size)) + { + if (size != 0) + { + addressSpaceContext.Vmm.Free(arguments.Offset, size); + } + } + else + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {arguments.Offset:x16}!"); + } + } + + return NvInternalResult.Success; + } + + private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments) + { + const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; + + AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(_owner); + + NvMapHandle map = NvMapFileDevice.GetMapFromHandle(_owner, arguments.NvMapHandle, true); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + long pa; + + if ((arguments.Flags & FlagRemapSubRange) != 0) + { + lock (addressSpaceContext) + { + if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out pa)) + { + long va = arguments.Offset + arguments.BufferOffset; + + pa += arguments.BufferOffset; + + if (addressSpaceContext.Vmm.Map(pa, va, arguments.MappingSize) < 0) + { + string msg = string.Format(mapErrorMsg, va, arguments.MappingSize); + + Logger.PrintWarning(LogClass.ServiceNv, msg); + + return NvInternalResult.InvalidInput; + } + + return NvInternalResult.Success; + } + else + { + Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{arguments.Offset:x16} not mapped!"); + + return NvInternalResult.InvalidInput; + } + } + } + + pa = map.Address + arguments.BufferOffset; + + long size = arguments.MappingSize; + + if (size == 0) + { + size = (uint)map.Size; + } + + NvInternalResult result = NvInternalResult.Success; + + lock (addressSpaceContext) + { + // Note: When the fixed offset flag is not set, + // the Offset field holds the alignment size instead. + bool vaAllocated = (arguments.Flags & FlagFixedOffset) == 0; + + if (!vaAllocated) + { + if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size)) + { + arguments.Offset = addressSpaceContext.Vmm.Map(pa, arguments.Offset, size); + } + else + { + string msg = string.Format(mapErrorMsg, arguments.Offset, size); + + Logger.PrintWarning(LogClass.ServiceNv, msg); + + result = NvInternalResult.InvalidInput; + } + } + else + { + arguments.Offset = addressSpaceContext.Vmm.Map(pa, size); + } + + if (arguments.Offset < 0) + { + arguments.Offset = 0; + + Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); + + result = NvInternalResult.InvalidInput; + } + else + { + addressSpaceContext.AddMap(arguments.Offset, size, pa, vaAllocated); + } + } + + return result; + } + + private NvInternalResult GetVaRegions(ref GetVaRegionsArguments arguments) + { + Logger.PrintStub(LogClass.ServiceNv); + + return NvInternalResult.Success; + } + + private NvInternalResult InitializeEx(ref InitializeExArguments arguments) + { + Logger.PrintStub(LogClass.ServiceNv); + + return NvInternalResult.Success; + } + + private NvInternalResult Remap(Span arguments) + { + for (int index = 0; index < arguments.Length; index++) + { + NvGpuVmm vmm = GetAddressSpaceContext(_owner).Vmm; + + NvMapHandle map = NvMapFileDevice.GetMapFromHandle(_owner, arguments[index].NvMapHandle, true); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments[index].NvMapHandle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + long result = vmm.Map(map.Address, (long)arguments[index].Offset << 16, + (long)arguments[index].Pages << 16); + + if (result < 0) + { + Logger.PrintWarning(LogClass.ServiceNv, + $"Page 0x{arguments[index].Offset:x16} size 0x{arguments[index].Pages:x16} not allocated!"); + + return NvInternalResult.InvalidInput; + } + } + + return NvInternalResult.Success; + } + + public override void Close() + { + // TODO + } + + public static AddressSpaceContext GetAddressSpaceContext(KProcess process) + { + return _addressSpaceContextRegistry.GetOrAdd(process, (key) => new AddressSpaceContext(process)); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AddressSpaceContext.cs similarity index 87% rename from Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs rename to Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AddressSpaceContext.cs index 315fe353ee..b124356907 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASCtx.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AddressSpaceContext.cs @@ -1,28 +1,32 @@ +using ARMeilleure.Memory; using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using System; using System.Collections.Generic; +using System.Text; -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types { - class NvGpuASCtx + class AddressSpaceContext { public NvGpuVmm Vmm { get; private set; } private class Range { - public ulong Start { get; private set; } - public ulong End { get; private set; } + public ulong Start { get; private set; } + public ulong End { get; private set; } public Range(long position, long size) { Start = (ulong)position; - End = (ulong)size + Start; + End = (ulong)size + Start; } } private class MappedMemory : Range { public long PhysicalAddress { get; private set; } - public bool VaAllocated { get; private set; } + public bool VaAllocated { get; private set; } public MappedMemory( long position, @@ -31,18 +35,18 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS bool vaAllocated) : base(position, size) { PhysicalAddress = physicalAddress; - VaAllocated = vaAllocated; + VaAllocated = vaAllocated; } } private SortedList _maps; private SortedList _reservations; - public NvGpuASCtx(ServiceCtx context) + public AddressSpaceContext(KProcess process) { - Vmm = new NvGpuVmm(context.Memory); + Vmm = new NvGpuVmm(process.CpuMemory); - _maps = new SortedList(); + _maps = new SortedList(); _reservations = new SortedList(); } @@ -135,7 +139,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS private Range BinarySearch(SortedList lst, long position) { - int left = 0; + int left = 0; int right = lst.Count - 1; while (left <= right) @@ -168,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS { Range ltRg = null; - int left = 0; + int left = 0; int right = lst.Count - 1; while (left <= right) @@ -197,4 +201,4 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS return ltRg; } } -} \ No newline at end of file +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AllocSpaceArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AllocSpaceArguments.cs new file mode 100644 index 0000000000..b8eee88c15 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AllocSpaceArguments.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct AllocSpaceArguments + { + public uint Pages; + public uint PageSize; + public uint Flags; + public uint Padding; + public long Offset; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/BindChannelArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/BindChannelArguments.cs new file mode 100644 index 0000000000..9c6568a3fe --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/BindChannelArguments.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct BindChannelArguments + { + public int Fd; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/FreeSpaceArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/FreeSpaceArguments.cs new file mode 100644 index 0000000000..a853974b4c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/FreeSpaceArguments.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct FreeSpaceArguments + { + public long Offset; + public uint Pages; + public uint PageSize; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs new file mode 100644 index 0000000000..6176bd31a4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct VaRegion + { + public ulong Offset; + public uint PageSize; + public uint Padding; + public ulong Pages; + } + + [StructLayout(LayoutKind.Sequential)] + struct GetVaRegionsArguments + { + public ulong Unused; + public uint BufferSize; + public uint Padding; + public VaRegion Region0; + public VaRegion Region1; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/InitializeExArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/InitializeExArguments.cs new file mode 100644 index 0000000000..882bda591f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/InitializeExArguments.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct InitializeExArguments + { + public uint Flags; + public int AsFd; + public uint BigPageSize; + public uint Reserved; + public ulong Unknown0; + public ulong Unknown1; + public ulong Unknown2; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/MapBufferExArguments.cs similarity index 54% rename from Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs rename to Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/MapBufferExArguments.cs index 6ef803774a..5672b79724 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuAS/Types/NvGpuASMapBufferEx.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/MapBufferExArguments.cs @@ -1,6 +1,9 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types { - struct NvGpuASMapBufferEx + [StructLayout(LayoutKind.Sequential)] + struct MapBufferExArguments { public int Flags; public int Kind; @@ -10,4 +13,4 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS public long MappingSize; public long Offset; } -} \ No newline at end of file +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/RemapArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/RemapArguments.cs new file mode 100644 index 0000000000..0cf324b453 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/RemapArguments.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct RemapArguments + { + public ushort Flags; + public ushort Kind; + public int NvMapHandle; + public int Padding; + public uint Offset; + public uint Pages; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/UnmapBufferArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/UnmapBufferArguments.cs new file mode 100644 index 0000000000..1ef880afea --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/UnmapBufferArguments.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types +{ + struct UnmapBufferArguments + { + public long Offset; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs index 0d06e7e419..b6328e4a7b 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelIoctl.cs @@ -2,7 +2,7 @@ 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.NvHostAsGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using System; using System.Collections.Concurrent; @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel _channels = new ConcurrentDictionary(); } - public static int ProcessIoctl(ServiceCtx context, int cmd) + public static NvInternalResult ProcessIoctl(ServiceCtx context, int cmd) { switch (cmd & 0xffff) { @@ -44,14 +44,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel throw new NotImplementedException(cmd.ToString("x8")); } - private static int Submit(ServiceCtx context) + private static NvInternalResult Submit(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; NvHostChannelSubmit args = MemoryHelper.Read(context.Memory, inputPosition); - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(context.Process).Vmm; for (int index = 0; index < args.CmdBufsCount; index++) { @@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel NvHostChannelCmdBuf cmdBuf = MemoryHelper.Read(context.Memory, cmdBufOffset); - NvMapHandle map = NvMapIoctl.GetNvMap(context, cmdBuf.MemoryId); + NvMapHandle map = NvMapFileDevice.GetMapFromHandle(context.Process, cmdBuf.MemoryId); int[] cmdBufData = new int[cmdBuf.WordsCount]; @@ -73,10 +73,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel // TODO: Relocation, waitchecks, etc. - return NvResult.Success; + return NvInternalResult.Success; } - private static int GetSyncpoint(ServiceCtx context) + private static NvInternalResult GetSyncpoint(ServiceCtx context) { // TODO long inputPosition = context.Request.GetBufferType0x21().Position; @@ -88,10 +88,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel MemoryHelper.Write(context.Memory, outputPosition, args); - return NvResult.Success; + return NvInternalResult.Success; } - private static int GetWaitBase(ServiceCtx context) + private static NvInternalResult GetWaitBase(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; @@ -102,10 +102,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel MemoryHelper.Write(context.Memory, outputPosition, args); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetSubmitTimeout(ServiceCtx context) + private static NvInternalResult SetSubmitTimeout(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; @@ -115,29 +115,29 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int MapBuffer(ServiceCtx context) + private static NvInternalResult MapBuffer(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; NvHostChannelMapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(context.Process).Vmm; for (int index = 0; index < args.NumEntries; index++) { int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8); - NvMapHandle map = NvMapIoctl.GetNvMap(context, handle); + NvMapHandle map = NvMapFileDevice.GetMapFromHandle(context.Process, handle); if (map == null) { Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!"); - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } lock (map) @@ -151,28 +151,28 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel } } - return NvResult.Success; + return NvInternalResult.Success; } - private static int UnmapBuffer(ServiceCtx context) + private static NvInternalResult UnmapBuffer(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; NvHostChannelMapBuffer args = MemoryHelper.Read(context.Memory, inputPosition); - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(context.Process).Vmm; for (int index = 0; index < args.NumEntries; index++) { int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8); - NvMapHandle map = NvMapIoctl.GetNvMap(context, handle); + NvMapHandle map = NvMapFileDevice.GetMapFromHandle(context.Process, handle); if (map == null) { Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!"); - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } lock (map) @@ -186,30 +186,30 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel } } - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetUserData(ServiceCtx context) + private static NvInternalResult SetUserData(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetNvMap(ServiceCtx context) + private static NvInternalResult SetNvMap(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetTimeout(ServiceCtx context) + private static NvInternalResult SetTimeout(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; @@ -217,17 +217,17 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SubmitGpfifo(ServiceCtx context) + private static NvInternalResult SubmitGpfifo(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; NvHostChannelSubmitGpfifo args = MemoryHelper.Read(context.Memory, inputPosition); - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(context.Process).Vmm; for (int index = 0; index < args.NumEntries; index++) { @@ -241,40 +241,40 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel MemoryHelper.Write(context.Memory, outputPosition, args); - return NvResult.Success; + return NvInternalResult.Success; } - private static int AllocObjCtx(ServiceCtx context) + private static NvInternalResult AllocObjCtx(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int ZcullBind(ServiceCtx context) + private static NvInternalResult ZcullBind(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetErrorNotifier(ServiceCtx context) + private static NvInternalResult SetErrorNotifier(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetPriority(ServiceCtx context) + private static NvInternalResult SetPriority(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; @@ -290,34 +290,34 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel GetChannel(context).Timeslice = 5200; // Timeslice high priority in micro-seconds break; default: - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } Logger.PrintStub(LogClass.ServiceNv); // TODO: disable and preempt channel when GPU scheduler will be implemented. - return NvResult.Success; + return NvInternalResult.Success; } - private static int AllocGpfifoEx2(ServiceCtx context) + private static NvInternalResult AllocGpfifoEx2(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int KickoffPbWithAttr(ServiceCtx context) + private static NvInternalResult KickoffPbWithAttr(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; NvHostChannelSubmitGpfifo args = MemoryHelper.Read(context.Memory, inputPosition); - NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm; + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(context.Process).Vmm; for (int index = 0; index < args.NumEntries; index++) { @@ -331,17 +331,17 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel MemoryHelper.Write(context.Memory, outputPosition, args); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SetTimeslice(ServiceCtx context) + private static NvInternalResult SetTimeslice(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; int timeslice = context.Memory.ReadInt32(inputPosition); if (timeslice < 1000 || timeslice > 50000) { - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } GetChannel(context).Timeslice = timeslice; // in micro-seconds @@ -350,7 +350,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel // TODO: disable and preempt channel when GPU scheduler will be implemented. - return NvResult.Success; + return NvInternalResult.Success; } private static void PushGpfifo(ServiceCtx context, NvGpuVmm vmm, long gpfifo) diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs new file mode 100644 index 0000000000..ebedaffd64 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs @@ -0,0 +1,92 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl.Types; +using Ryujinx.HLE.HOS.Services.Settings; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl +{ + internal class NvHostCtrlFileDevice : NvFileDevice + { + private bool _isProductionMode; + + public NvHostCtrlFileDevice(KProcess owner) : base(owner) + { + if (NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting)) + { + _isProductionMode = ((string)productionModeSetting) != "0"; // Default value is "" + } + } + + public override NvInternalResult Ioctl(NvIoctl command, Span arguments) + { + NvInternalResult result = NvInternalResult.NotImplemented; + + switch (command.GetNumberValue()) + { + case 0x1b: + // As Marshal cannot handle unaligned arrays, we do everything by hand here. + NvHostCtrlGetConfigurationArgument configArgument = NvHostCtrlGetConfigurationArgument.FromSpan(arguments); + result = GetConfig(configArgument); + + if (result == NvInternalResult.Success) + { + configArgument.CopyTo(arguments); + } + break; + default: + break; + } + + return result; + } + + private NvInternalResult GetConfig(NvHostCtrlGetConfigurationArgument arguments) + { + if (!_isProductionMode && NxSettings.Settings.TryGetValue($"{arguments.Domain}!{arguments.Parameter}".ToLower(), out object nvSetting)) + { + byte[] settingBuffer = new byte[0x101]; + + if (nvSetting is string stringValue) + { + if (stringValue.Length > 0x100) + { + Logger.PrintError(LogClass.ServiceNv, $"{arguments.Domain}!{arguments.Parameter} String value size is too big!"); + } + else + { + settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0"); + } + } + else if (nvSetting is int intValue) + { + settingBuffer = BitConverter.GetBytes(intValue); + } + else if (nvSetting is bool boolValue) + { + settingBuffer[0] = boolValue ? (byte)1 : (byte)0; + } + else + { + throw new NotImplementedException(nvSetting.GetType().Name); + } + + Logger.PrintDebug(LogClass.ServiceNv, $"Got setting {arguments.Domain}!{arguments.Parameter}"); + + arguments.Configuration = settingBuffer; + + return NvInternalResult.Success; + } + + // NOTE: This actually return NotAvailableInProduction but this is directly translated as a InvalidInput before returning the ioctl. + //return NvInternalResult.NotAvailableInProduction; + return NvInternalResult.InvalidInput; + } + + public override void Close() + { + // TODO + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs index 346e2dc769..14261a75e5 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlIoctl.cs @@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl } } - public static int ProcessIoctl(ServiceCtx context, int cmd) + public static NvInternalResult ProcessIoctl(ServiceCtx context, int cmd) { switch (cmd & 0xffff) { @@ -43,12 +43,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl throw new NotImplementedException(cmd.ToString("x8")); } - private static int SyncptRead(ServiceCtx context) + private static NvInternalResult SyncptRead(ServiceCtx context) { return SyncptReadMinOrMax(context, max: false); } - private static int SyncptIncr(ServiceCtx context) + private static NvInternalResult SyncptIncr(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; @@ -56,30 +56,30 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl if ((uint)id >= NvHostSyncpt.SyncptsCount) { - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } GetUserCtx(context).Syncpt.Increment(id); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SyncptWait(ServiceCtx context) + private static NvInternalResult SyncptWait(ServiceCtx context) { return SyncptWait(context, extended: false); } - private static int SyncptWaitEx(ServiceCtx context) + private static NvInternalResult SyncptWaitEx(ServiceCtx context) { return SyncptWait(context, extended: true); } - private static int SyncptReadMax(ServiceCtx context) + private static NvInternalResult SyncptReadMax(ServiceCtx context) { return SyncptReadMinOrMax(context, max: true); } - private static int GetConfig(ServiceCtx context) + private static NvInternalResult GetConfig(ServiceCtx context) { if (!_isProductionMode) { @@ -123,23 +123,25 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl Logger.PrintDebug(LogClass.ServiceNv, $"Got setting {domain}!{name}"); } - return NvResult.Success; + return NvInternalResult.Success; } - return NvResult.NotAvailableInProduction; + // NOTE: This actually return NotAvailableInProduction but this is directly translated as a InvalidInput before returning the ioctl. + //return NvInternalResult.NotAvailableInProduction; + return NvInternalResult.InvalidInput; } - private static int EventWait(ServiceCtx context) + private static NvInternalResult EventWait(ServiceCtx context) { return EventWait(context, async: false); } - private static int EventWaitAsync(ServiceCtx context) + private static NvInternalResult EventWaitAsync(ServiceCtx context) { return EventWait(context, async: true); } - private static int EventRegister(ServiceCtx context) + private static NvInternalResult EventRegister(ServiceCtx context) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; @@ -148,10 +150,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl Logger.PrintStub(LogClass.ServiceNv); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SyncptReadMinOrMax(ServiceCtx context, bool max) + private static NvInternalResult SyncptReadMinOrMax(ServiceCtx context, bool max) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; @@ -160,7 +162,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) { - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } if (max) @@ -174,10 +176,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl MemoryHelper.Write(context.Memory, outputPosition, args); - return NvResult.Success; + return NvInternalResult.Success; } - private static int SyncptWait(ServiceCtx context, bool extended) + private static NvInternalResult SyncptWait(ServiceCtx context, bool extended) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; @@ -188,18 +190,18 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) { - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } - int result; + NvInternalResult result; if (syncpt.MinCompare(args.Id, args.Thresh)) { - result = NvResult.Success; + result = NvInternalResult.Success; } else if (args.Timeout == 0) { - result = NvResult.TryAgain; + result = NvInternalResult.TryAgain; } else { @@ -222,15 +224,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl { waitEvent.WaitOne(); - result = NvResult.Success; + result = NvInternalResult.Success; } else if (waitEvent.WaitOne(timeout)) { - result = NvResult.Success; + result = NvInternalResult.Success; } else { - result = NvResult.TimedOut; + result = NvInternalResult.TimedOut; } } @@ -245,7 +247,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl return result; } - private static int EventWait(ServiceCtx context, bool async) + private static NvInternalResult EventWait(ServiceCtx context, bool async) { long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; @@ -254,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl if ((uint)args.Id >= NvHostSyncpt.SyncptsCount) { - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } void WriteArgs() @@ -270,7 +272,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl WriteArgs(); - return NvResult.Success; + return NvInternalResult.Success; } if (!async) @@ -282,12 +284,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl { WriteArgs(); - return NvResult.TryAgain; + return NvInternalResult.TryAgain; } NvHostEvent Event; - int result, eventIndex; + NvInternalResult result; + + int eventIndex; if (async) { @@ -295,7 +299,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl if ((uint)eventIndex >= NvHostCtrlUserCtx.EventsCount) { - return NvResult.InvalidInput; + return NvInternalResult.InvalidInput; } Event = GetUserCtx(context).Events[eventIndex]; @@ -325,11 +329,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl args.Value |= eventIndex; - result = NvResult.TryAgain; + result = NvInternalResult.TryAgain; } else { - result = NvResult.InvalidInput; + result = NvInternalResult.InvalidInput; } WriteArgs(); diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlGetConfigurationArgument.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlGetConfigurationArgument.cs new file mode 100644 index 0000000000..bae194aff3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostCtrlGetConfigurationArgument.cs @@ -0,0 +1,34 @@ +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl.Types +{ + class NvHostCtrlGetConfigurationArgument + { + public string Domain; + public string Parameter; + public byte[] Configuration; + + public static NvHostCtrlGetConfigurationArgument FromSpan(Span span) + { + string domain = Encoding.ASCII.GetString(span.Slice(0, 0x41)); + string parameter = Encoding.ASCII.GetString(span.Slice(0x41, 0x41)); + + NvHostCtrlGetConfigurationArgument result = new NvHostCtrlGetConfigurationArgument + { + Domain = domain.Substring(0, domain.IndexOf('\0')), + Parameter = parameter.Substring(0, parameter.IndexOf('\0')), + Configuration = span.Slice(0x82, 0x101).ToArray() + }; + + return result; + } + + public void CopyTo(Span span) + { + Encoding.ASCII.GetBytes(Domain + '\0').CopyTo(span.Slice(0, 0x41)); + Encoding.ASCII.GetBytes(Parameter + '\0').CopyTo(span.Slice(0x41, 0x41)); + Configuration.CopyTo(span.Slice(0x82, 0x101)); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs new file mode 100644 index 0000000000..5f85a6384e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs @@ -0,0 +1,167 @@ +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types; +using System; +using System.Diagnostics; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu +{ + class NvHostCtrlGpuFileDevice : NvFileDevice + { + private static Stopwatch _pTimer = new Stopwatch(); + private static double _ticksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; + + public NvHostCtrlGpuFileDevice(KProcess owner) : base(owner) + { + } + + static NvHostCtrlGpuFileDevice() + { + _pTimer.Start(); + } + + public override NvInternalResult Ioctl(NvIoctl command, Span arguments) + { + NvInternalResult result = NvInternalResult.NotImplemented; + + switch (command.GetNumberValue()) + { + case 0x1: + result = CallIoctlMethod(ZcullGetCtxSize, arguments); + break; + case 0x2: + result = CallIoctlMethod(ZcullGetInfo, arguments); + break; + case 0x3: + result = CallIoctlMethod(ZbcSetTable, arguments); + break; + case 0x5: + result = CallIoctlMethod(GetCharacteristics, arguments); + break; + case 0x6: + result = CallIoctlMethod(GetTpcMasks, arguments); + break; + case 0x14: + result = CallIoctlMethod(GetActiveSlotMask, arguments); + break; + case 0x1c: + result = CallIoctlMethod(GetGpuTime, arguments); + break; + } + + return result; + } + + public override void Close() + { + // TODO + } + + private NvInternalResult ZcullGetCtxSize(ref ZcullGetCtxSizeArguments arguments) + { + arguments.Size = 1; + + return NvInternalResult.Success; + } + + private NvInternalResult ZcullGetInfo(ref ZcullGetInfoArguments arguments) + { + arguments.WidthAlignPixels = 0x20; + arguments.HeightAlignPixels = 0x20; + arguments.PixelSquaresByAliquots = 0x400; + arguments.AliquotTotal = 0x800; + arguments.RegionByteMultiplier = 0x20; + arguments.RegionHeaderSize = 0x20; + arguments.SubregionHeaderSize = 0xc0; + arguments.SubregionWidthAlignPixels = 0x20; + arguments.SubregionHeightAlignPixels = 0x40; + arguments.SubregionCount = 0x10; + + return NvInternalResult.Success; + } + + private NvInternalResult ZbcSetTable(ref ZbcSetTableArguments arguments) + { + Logger.PrintStub(LogClass.ServiceNv); + + return NvInternalResult.Success; + } + + private NvInternalResult GetCharacteristics(ref GetCharacteristicsArguments arguments) + { + arguments.BufferSize = 0xa0; + + arguments.Characteristics.Arch = 0x120; + arguments.Characteristics.Impl = 0xb; + arguments.Characteristics.Rev = 0xa1; + arguments.Characteristics.NumGpc = 0x1; + arguments.Characteristics.L2CacheSize = 0x40000; + arguments.Characteristics.OnBoardVideoMemorySize = 0x0; + arguments.Characteristics.NumTpcPerGpc = 0x2; + arguments.Characteristics.BusType = 0x20; + arguments.Characteristics.BigPageSize = 0x20000; + arguments.Characteristics.CompressionPageSize = 0x20000; + arguments.Characteristics.PdeCoverageBitCount = 0x1b; + arguments.Characteristics.AvailableBigPageSizes = 0x30000; + arguments.Characteristics.GpcMask = 0x1; + arguments.Characteristics.SmArchSmVersion = 0x503; + arguments.Characteristics.SmArchSpaVersion = 0x503; + arguments.Characteristics.SmArchWarpCount = 0x80; + arguments.Characteristics.GpuVaBitCount = 0x28; + arguments.Characteristics.Reserved = 0x0; + arguments.Characteristics.Flags = 0x55; + arguments.Characteristics.TwodClass = 0x902d; + arguments.Characteristics.ThreedClass = 0xb197; + arguments.Characteristics.ComputeClass = 0xb1c0; + arguments.Characteristics.GpfifoClass = 0xb06f; + arguments.Characteristics.InlineToMemoryClass = 0xa140; + arguments.Characteristics.DmaCopyClass = 0xb0b5; + arguments.Characteristics.MaxFbpsCount = 0x1; + arguments.Characteristics.FbpEnMask = 0x0; + arguments.Characteristics.MaxLtcPerFbp = 0x2; + arguments.Characteristics.MaxLtsPerLtc = 0x1; + arguments.Characteristics.MaxTexPerTpc = 0x0; + arguments.Characteristics.MaxGpcCount = 0x1; + arguments.Characteristics.RopL2EnMask0 = 0x21d70; + arguments.Characteristics.RopL2EnMask1 = 0x0; + arguments.Characteristics.ChipName = 0x6230326d67; + arguments.Characteristics.GrCompbitStoreBaseHw = 0x0; + + return NvInternalResult.Success; + } + + private NvInternalResult GetTpcMasks(ref GetTpcMasksArguments arguments) + { + if (arguments.MaskBufferSize != 0) + { + arguments.TpcMask = 3; + } + + return NvInternalResult.Success; + } + + private NvInternalResult GetActiveSlotMask(ref GetActiveSlotMaskArguments arguments) + { + Logger.PrintStub(LogClass.ServiceNv); + + arguments.Slot = 0x07; + arguments.Mask = 0x01; + + return NvInternalResult.Success; + } + + private NvInternalResult GetGpuTime(ref GetGpuTimeArguments arguments) + { + arguments.Timestamp = GetPTimerNanoSeconds(); + + return NvInternalResult.Success; + } + + private static ulong GetPTimerNanoSeconds() + { + double ticks = _pTimer.ElapsedTicks; + + return (ulong)(ticks * _ticksToNs) & 0xff_ffff_ffff_ffff; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetActiveSlotMaskArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetActiveSlotMaskArguments.cs new file mode 100644 index 0000000000..fd73be9e79 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetActiveSlotMaskArguments.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct GetActiveSlotMaskArguments + { + public int Slot; + public int Mask; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetCharacteristicsArguments.cs similarity index 73% rename from Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs rename to Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetCharacteristicsArguments.cs index 76aef2a782..d313bb3c84 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuGetCharacteristics.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetCharacteristicsArguments.cs @@ -1,9 +1,10 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types { - struct NvGpuGpuGetCharacteristics + [StructLayout(LayoutKind.Sequential)] + struct GpuCharacteristics { - public long BufferSize; - public long BufferAddress; public int Arch; public int Impl; public int Rev; @@ -40,4 +41,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu public long ChipName; public long GrCompbitStoreBaseHw; } -} \ No newline at end of file + + [StructLayout(LayoutKind.Sequential)] + struct GetCharacteristicsArguments + { + public long BufferSize; + public long BufferAddress; + public GpuCharacteristics Characteristics; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetGpuTimeArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetGpuTimeArguments.cs new file mode 100644 index 0000000000..084ef71fb5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetGpuTimeArguments.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct GetGpuTimeArguments + { + public ulong Timestamp; + public ulong Reserved; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetTpcMasksArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetTpcMasksArguments.cs new file mode 100644 index 0000000000..2ae1b42fb9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/GetTpcMasksArguments.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct GetTpcMasksArguments + { + public int MaskBufferSize; + public int Reserved; + public long MaskBufferAddress; + public int TpcMask; + public int Padding; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZbcSetTableArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZbcSetTableArguments.cs new file mode 100644 index 0000000000..ceed2acc16 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZbcSetTableArguments.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct ZbcSetTableArguments + { + + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZcullGetCtxSizeArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZcullGetCtxSizeArguments.cs new file mode 100644 index 0000000000..1e668f867a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZcullGetCtxSizeArguments.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types +{ + [StructLayout(LayoutKind.Sequential)] + struct ZcullGetCtxSizeArguments + { + public int Size; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZcullGetInfoArguments.cs similarity index 68% rename from Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs rename to Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZcullGetInfoArguments.cs index ab17ca8b9c..d0d152a3de 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvGpuGpu/Types/NvGpuGpuZcullGetInfo.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/Types/ZcullGetInfoArguments.cs @@ -1,6 +1,9 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuGpu +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types { - struct NvGpuGpuZcullGetInfo + [StructLayout(LayoutKind.Sequential)] + struct ZcullGetInfoArguments { public int WidthAlignPixels; public int HeightAlignPixels; @@ -13,4 +16,4 @@ public int SubregionHeightAlignPixels; public int SubregionCount; } -} \ No newline at end of file +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvInternalResult.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvInternalResult.cs new file mode 100644 index 0000000000..9345baeb57 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvInternalResult.cs @@ -0,0 +1,32 @@ +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices +{ + enum NvInternalResult : int + { + Success = 0, + OperationNotPermitted = -1, + NoEntry = -2, + Interrupted = -4, + IoError = -5, + DeviceNotFound = -6, + BadFileNumber = -9, + TryAgain = -11, + OutOfMemory = -12, + AccessDenied = -13, + BadAddress = -14, + Busy = -16, + NotADirectory = -20, + InvalidInput = -22, + FileTableOverflow = -23, + Unknown0x18 = -24, + NotSupported = -25, + FileTooBig = -27, + NoSpaceLeft = -28, + ReadOnlyAttribute = -30, + NotImplemented = -38, + InvalidState = -40, + Restart = -85, + InvalidAddress = -99, + TimedOut = -110, + Unknown0x72 = -114, + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapFileDevice.cs new file mode 100644 index 0000000000..f7d8dec981 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapFileDevice.cs @@ -0,0 +1,268 @@ +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel.Process; +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap +{ + internal class NvMapFileDevice : NvFileDevice + { + private const int FlagNotFreedYet = 1; + + private static ConcurrentDictionary _maps = new ConcurrentDictionary(); + + public NvMapFileDevice(KProcess owner) : base(owner) + { + IdDictionary dict = _maps.GetOrAdd(owner, (key) => new IdDictionary()); + + dict.Add(0, new NvMapHandle()); + } + + public override NvInternalResult Ioctl(NvIoctl command, Span arguments) + { + NvInternalResult result = NvInternalResult.NotImplemented; + + switch (command.GetNumberValue()) + { + case 0x1: + result = CallIoctlMethod(Create, arguments); + break; + case 0x3: + result = CallIoctlMethod(FromId, arguments); + break; + case 0x4: + result = CallIoctlMethod(Alloc, arguments); + break; + case 0x5: + result = CallIoctlMethod(Free, arguments); + break; + case 0x9: + result = CallIoctlMethod(Param, arguments); + break; + case 0xe: + result = CallIoctlMethod(GetId, arguments); + break; + case 0x2: + case 0x6: + case 0x7: + case 0x8: + case 0xa: + case 0xc: + case 0xd: + case 0xf: + case 0x10: + case 0x11: + result = NvInternalResult.NotSupported; + break; + } + + return result; + } + + private NvInternalResult Create(ref NvMapCreate arguments) + { + if (arguments.Size == 0) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{arguments.Size:x8}!"); + + return NvInternalResult.InvalidInput; + } + + int size = BitUtils.AlignUp(arguments.Size, NvGpuVmm.PageSize); + + arguments.Handle = CreateHandleFromMap(new NvMapHandle(size)); + + Logger.PrintInfo(LogClass.ServiceNv, $"Created map {arguments.Handle} with size 0x{size:x8}!"); + + return NvInternalResult.Success; + } + + private NvInternalResult FromId(ref NvMapFromId arguments) + { + NvMapHandle map = GetMapFromHandle(_owner, arguments.Id); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + map.IncrementRefCount(); + + arguments.Handle = arguments.Id; + + return NvInternalResult.Success; + } + + private NvInternalResult Alloc(ref NvMapAlloc arguments) + { + NvMapHandle map = GetMapFromHandle(_owner, arguments.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + if ((arguments.Align & (arguments.Align - 1)) != 0) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{arguments.Align:x8}!"); + + return NvInternalResult.InvalidInput; + } + + if ((uint)arguments.Align < NvGpuVmm.PageSize) + { + arguments.Align = NvGpuVmm.PageSize; + } + + NvInternalResult result = NvInternalResult.Success; + + if (!map.Allocated) + { + map.Allocated = true; + + map.Align = arguments.Align; + map.Kind = (byte)arguments.Kind; + + int size = BitUtils.AlignUp(map.Size, NvGpuVmm.PageSize); + + long address = arguments.Address; + + if (address == 0) + { + // When the address is zero, we need to allocate + // our own backing memory for the NvMap. + // TODO: Is this allocation inside the transfer memory? + result = NvInternalResult.OutOfMemory; + } + + if (result == NvInternalResult.Success) + { + map.Size = size; + map.Address = address; + } + } + + return result; + } + + private NvInternalResult Free(ref NvMapFree arguments) + { + NvMapHandle map = GetMapFromHandle(_owner, arguments.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + if (map.DecrementRefCount() <= 0) + { + DeleteMapWithHandle(arguments.Handle); + + Logger.PrintInfo(LogClass.ServiceNv, $"Deleted map {arguments.Handle}!"); + + arguments.Address = map.Address; + arguments.Flags = 0; + } + else + { + arguments.Address = 0; + arguments.Flags = FlagNotFreedYet; + } + + arguments.Size = map.Size; + + return NvInternalResult.Success; + } + + private NvInternalResult Param(ref NvMapParam arguments) + { + NvMapHandle map = GetMapFromHandle(_owner, arguments.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + switch (arguments.Param) + { + case NvMapHandleParam.Size: arguments.Result = map.Size; break; + case NvMapHandleParam.Align: arguments.Result = map.Align; break; + case NvMapHandleParam.Heap: arguments.Result = 0x40000000; break; + case NvMapHandleParam.Kind: arguments.Result = map.Kind; break; + case NvMapHandleParam.Compr: arguments.Result = 0; break; + + // Note: Base is not supported and returns an error. + // Any other value also returns an error. + default: return NvInternalResult.InvalidInput; + } + + return NvInternalResult.Success; + } + + private NvInternalResult GetId(ref NvMapGetId arguments) + { + NvMapHandle map = GetMapFromHandle(_owner, arguments.Handle); + + if (map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!"); + + return NvInternalResult.InvalidInput; + } + + arguments.Id = arguments.Handle; + + return NvInternalResult.Success; + } + + public override void Close() + { + // TODO: refcount NvMapFileDevice instances and remove when closing + // _maps.TryRemove(GetOwner(), out _); + } + + private int CreateHandleFromMap(NvMapHandle map) + { + IdDictionary dict = _maps.GetOrAdd(_owner, (key) => + { + IdDictionary newDict = new IdDictionary(); + + newDict.Add(0, new NvMapHandle()); + + return newDict; + }); + + return dict.Add(map); + } + + private bool DeleteMapWithHandle(int handle) + { + if (_maps.TryGetValue(_owner, out IdDictionary dict)) + { + return dict.Delete(handle) != null; + } + + return false; + } + + public static NvMapHandle GetMapFromHandle(KProcess process, int handle, bool allowHandleZero = false) + { + if ((allowHandleZero || handle != 0) && _maps.TryGetValue(process, out IdDictionary dict)) + { + return dict.GetData(handle); + } + + return null; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs deleted file mode 100644 index e46da4fde3..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapIoctl.cs +++ /dev/null @@ -1,300 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Memory; -using Ryujinx.HLE.HOS.Kernel.Process; -using System.Collections.Concurrent; - -namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap -{ - class NvMapIoctl - { - private const int FlagNotFreedYet = 1; - - private static ConcurrentDictionary _maps; - - static NvMapIoctl() - { - _maps = new ConcurrentDictionary(); - } - - public static int ProcessIoctl(ServiceCtx context, int cmd) - { - switch (cmd & 0xffff) - { - case 0x0101: return Create(context); - case 0x0103: return FromId(context); - case 0x0104: return Alloc (context); - case 0x0105: return Free (context); - case 0x0109: return Param (context); - case 0x010e: return GetId (context); - } - - Logger.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{cmd:x8}!"); - - return NvResult.NotSupported; - } - - private static int Create(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapCreate args = MemoryHelper.Read(context.Memory, inputPosition); - - if (args.Size == 0) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{args.Size:x8}!"); - - return NvResult.InvalidInput; - } - - int size = BitUtils.AlignUp(args.Size, NvGpuVmm.PageSize); - - args.Handle = AddNvMap(context, new NvMapHandle(size)); - - Logger.PrintInfo(LogClass.ServiceNv, $"Created map {args.Handle} with size 0x{size:x8}!"); - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int FromId(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapFromId args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Id); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - map.IncrementRefCount(); - - args.Handle = args.Id; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int Alloc(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapAlloc args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - if ((args.Align & (args.Align - 1)) != 0) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{args.Align:x8}!"); - - return NvResult.InvalidInput; - } - - if ((uint)args.Align < NvGpuVmm.PageSize) - { - args.Align = NvGpuVmm.PageSize; - } - - int result = NvResult.Success; - - if (!map.Allocated) - { - map.Allocated = true; - - map.Align = args.Align; - map.Kind = (byte)args.Kind; - - int size = BitUtils.AlignUp(map.Size, NvGpuVmm.PageSize); - - long address = args.Address; - - if (address == 0) - { - // When the address is zero, we need to allocate - // our own backing memory for the NvMap. - // TODO: Is this allocation inside the transfer memory? - result = NvResult.OutOfMemory; - } - - if (result == NvResult.Success) - { - map.Size = size; - map.Address = address; - } - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return result; - } - - private static int Free(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapFree args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - if (map.DecrementRefCount() <= 0) - { - DeleteNvMap(context, args.Handle); - - Logger.PrintInfo(LogClass.ServiceNv, $"Deleted map {args.Handle}!"); - - args.Address = map.Address; - args.Flags = 0; - } - else - { - args.Address = 0; - args.Flags = FlagNotFreedYet; - } - - args.Size = map.Size; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int Param(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapParam args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - switch ((NvMapHandleParam)args.Param) - { - case NvMapHandleParam.Size: args.Result = map.Size; break; - case NvMapHandleParam.Align: args.Result = map.Align; break; - case NvMapHandleParam.Heap: args.Result = 0x40000000; break; - case NvMapHandleParam.Kind: args.Result = map.Kind; break; - case NvMapHandleParam.Compr: args.Result = 0; break; - - // Note: Base is not supported and returns an error. - // Any other value also returns an error. - default: return NvResult.InvalidInput; - } - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int GetId(ServiceCtx context) - { - long inputPosition = context.Request.GetBufferType0x21().Position; - long outputPosition = context.Request.GetBufferType0x22().Position; - - NvMapGetId args = MemoryHelper.Read(context.Memory, inputPosition); - - NvMapHandle map = GetNvMap(context, args.Handle); - - if (map == null) - { - Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!"); - - return NvResult.InvalidInput; - } - - args.Id = args.Handle; - - MemoryHelper.Write(context.Memory, outputPosition, args); - - return NvResult.Success; - } - - private static int AddNvMap(ServiceCtx context, NvMapHandle map) - { - IdDictionary dict = _maps.GetOrAdd(context.Process, (key) => - { - IdDictionary newDict = new IdDictionary(); - - newDict.Add(0, new NvMapHandle()); - - return newDict; - }); - - return dict.Add(map); - } - - private static bool DeleteNvMap(ServiceCtx context, int handle) - { - if (_maps.TryGetValue(context.Process, out IdDictionary dict)) - { - return dict.Delete(handle) != null; - } - - return false; - } - - public static void InitializeNvMap(ServiceCtx context) - { - IdDictionary dict = _maps.GetOrAdd(context.Process, (key) =>new IdDictionary()); - - dict.Add(0, new NvMapHandle()); - } - - public static NvMapHandle GetNvMapWithFb(ServiceCtx context, int handle) - { - if (_maps.TryGetValue(context.Process, out IdDictionary dict)) - { - return dict.GetData(handle); - } - - return null; - } - - public static NvMapHandle GetNvMap(ServiceCtx context, int handle) - { - if (handle != 0 && _maps.TryGetValue(context.Process, out IdDictionary dict)) - { - return dict.GetData(handle); - } - - return null; - } - - public static void UnloadProcess(KProcess process) - { - _maps.TryRemove(process, out _); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs index f449b60675..efc0f2aa3b 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapAlloc.cs @@ -1,5 +1,8 @@ +using System.Runtime.InteropServices; + namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { + [StructLayout(LayoutKind.Sequential)] struct NvMapAlloc { public int Handle; diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs index b1ccf1bc9a..b47e462941 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs @@ -1,5 +1,8 @@ +using System.Runtime.InteropServices; + namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { + [StructLayout(LayoutKind.Sequential)] struct NvMapCreate { public int Size; diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs index 1d17c3a7d4..d142b9f301 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs @@ -1,5 +1,8 @@ +using System.Runtime.InteropServices; + namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { + [StructLayout(LayoutKind.Sequential)] struct NvMapFree { public int Handle; diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs index 7f7f83ab87..2e559534d1 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFromId.cs @@ -1,5 +1,8 @@ +using System.Runtime.InteropServices; + namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { + [StructLayout(LayoutKind.Sequential)] struct NvMapFromId { public int Id; diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs index df8fff5385..fe574eea5d 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapGetId.cs @@ -1,5 +1,8 @@ +using System.Runtime.InteropServices; + namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { + [StructLayout(LayoutKind.Sequential)] struct NvMapGetId { public int Id; diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs index 9eb7efff95..61b73cba2e 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandleParam.cs @@ -1,6 +1,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { - enum NvMapHandleParam + enum NvMapHandleParam : int { Size = 1, Align = 2, diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs index c873a0d24b..de5bab770d 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapParam.cs @@ -1,9 +1,12 @@ +using System.Runtime.InteropServices; + namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap { + [StructLayout(LayoutKind.Sequential)] struct NvMapParam { - public int Handle; - public int Param; - public int Result; + public int Handle; + public NvMapHandleParam Param; + public int Result; } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvIoctl.cs new file mode 100644 index 0000000000..2a2fd15bf0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvIoctl.cs @@ -0,0 +1,54 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv +{ + [StructLayout(LayoutKind.Sequential)] + struct NvIoctl + { + private const int NumberBits = 8; + private const int TypeBits = 8; + private const int SizeBits = 14; + private const int DirectionBits = 2; + + private const int NumberShift = 0; + private const int TypeShift = NumberShift + NumberBits; + private const int SizeShift = TypeShift + TypeBits; + private const int DirectionShift = SizeShift + SizeBits; + + private const int NumberMask = (1 << NumberBits) - 1; + private const int TypeMask = (1 << TypeBits) - 1; + private const int SizeMask = (1 << SizeBits) - 1; + private const int DirectionMask = (1 << DirectionBits) - 1; + + [Flags] + public enum Direction : uint + { + None = 0, + Read = 1, + Write = 2, + } + + public uint RawValue; + + public uint GetNumberValue() + { + return (RawValue >> NumberShift) & NumberMask; + } + + public uint GetTypeValue() + { + return (RawValue >> TypeShift) & TypeMask; + } + + public uint GetSizeValue() + { + return (RawValue >> SizeShift) & SizeMask; + } + + public Direction GetDirectionValue() + { + return (Direction)((RawValue >> DirectionShift) & DirectionMask); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs deleted file mode 100644 index b6c654e4ea..0000000000 --- a/Ryujinx.HLE/HOS/Services/Nv/Types/NvFd.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv -{ - class NvFd - { - public string Name { get; private set; } - - public NvFd(string name) - { - Name = name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs new file mode 100644 index 0000000000..0ec4e67429 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs @@ -0,0 +1,52 @@ +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Nv.Types +{ + class NvIoctlNotImplementedException : Exception + { + public ServiceCtx Context { get; } + public NvFileDevice FileDevice { get; } + public NvIoctl Command { get; } + + public NvIoctlNotImplementedException(ServiceCtx context, NvFileDevice fileDevice, NvIoctl command) + : this(context, fileDevice, command, "The ioctl is not implemented.") + { } + + public NvIoctlNotImplementedException(ServiceCtx context, NvFileDevice fileDevice, NvIoctl command, string message) + : base(message) + { + Context = context; + FileDevice = fileDevice; + Command = command; + } + + public override string Message + { + get + { + return base.Message + + Environment.NewLine + + Environment.NewLine + + BuildMessage(); + } + } + + private string BuildMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendLine($"Ioctl (0x{Command.RawValue:x8})"); + sb.AppendLine($"\tNumber: 0x{Command.GetNumberValue():x8}"); + sb.AppendLine($"\tType: 0x{Command.GetTypeValue():x8}"); + sb.AppendLine($"\tSize: 0x{Command.GetSizeValue():x8}"); + sb.AppendLine($"\tDirection: {Command.GetDirectionValue()}"); + + sb.AppendLine("Guest Stack Trace:"); + sb.AppendLine(Context.Thread.GetGuestStackTrace()); + + return sb.ToString(); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs index 362a045026..1c9cae8ca6 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/Types/NvResult.cs @@ -1,14 +1,30 @@ namespace Ryujinx.HLE.HOS.Services.Nv { - static class NvResult + enum NvResult : uint { - public const int NotAvailableInProduction = 196614; - public const int Success = 0; - public const int TryAgain = -11; - public const int OutOfMemory = -12; - public const int InvalidInput = -22; - public const int NotSupported = -25; - public const int Restart = -85; - public const int TimedOut = -110; + Success = 0, + NotImplemented = 1, + NotSupported = 2, + NotInitialized = 3, + InvalidParameter = 4, + Timeout = 5, + InsufficientMemory = 6, + ReadOnlyAttribute = 7, + InvalidState = 8, + InvalidAddress = 9, + InvalidSize = 10, + InvalidValue = 11, + AlreadyAllocated = 13, + Busy = 14, + ResourceError = 15, + CountMismatch = 16, + SharedMemoryTooSmall = 0x1000, + FileOperationFailed = 0x30003, + DirectoryOperationFailed = 0x30004, + NotAvailableInProduction = 0x30006, + IoctlFailed = 0x3000F, + AccessDenied = 0x30010, + FileNotFound = 0x30013, + ModuleNotPresent = 0xA000E, } } \ No newline at end of file