diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index 5e78d1f66f..4d09908066 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -24,7 +24,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv [Service("nvdrv:t")] class INvDrvServices : IpcService { - // TODO: everything private static Dictionary _fileDeviceRegistry = new Dictionary() { @@ -329,7 +328,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv if (errorCode == NvResult.Success) { - errorCode = ConvertInternalErrorCode(fileDevice.QueryEvent(out int eventHandle, eventId)); + NvInternalResult internalResult = fileDevice.QueryEvent(out int eventHandle, eventId); + + if (internalResult == NvInternalResult.NotImplemented) + { + throw new NvQueryEventlNotImplementedException(context, fileDevice, eventId); + } + + errorCode = ConvertInternalErrorCode(internalResult); if (errorCode == NvResult.Success) { diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs index 74b253784d..bbfd70b47c 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs @@ -1,12 +1,21 @@ -using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types; using System; namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel { internal class NvHostGpuFileDevice : NvHostChannelFileDevice { + private KEvent _smExceptionBptIntReportEvent; + private KEvent _smExceptionBptPauseReportEvent; + private KEvent _errorNotifierEvent; + public NvHostGpuFileDevice(ServiceCtx context) : base(context) { + _smExceptionBptIntReportEvent = new KEvent(context.Device.System); + _smExceptionBptPauseReportEvent = new KEvent(context.Device.System); + _errorNotifierEvent = new KEvent(context.Device.System); } public override NvInternalResult Ioctl2(NvIoctl command, Span arguments, Span inlineInBuffer) @@ -25,6 +34,41 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel return result; } + public override NvInternalResult QueryEvent(out int eventHandle, uint eventId) + { + // TODO: accurately represent and implement those events. + KEvent targetEvent = null; + + switch (eventId) + { + case 0x1: + targetEvent = _smExceptionBptIntReportEvent; + break; + case 0x2: + targetEvent = _smExceptionBptPauseReportEvent; + break; + case 0x3: + targetEvent = _errorNotifierEvent; + break; + } + + if (targetEvent != null) + { + if (_owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + else + { + eventHandle = 0; + + return NvInternalResult.InvalidInput; + } + + return NvInternalResult.Success; + } + private NvInternalResult SubmitGpfifoEx(ref SubmitGpfifoArguments arguments, Span inlineData) { return SubmitGpfifo(ref arguments, inlineData); diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs index 72f9d91e5a..012528fe70 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/NvHostCtrlFileDevice.cs @@ -1,4 +1,6 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl.Types; using Ryujinx.HLE.HOS.Services.Nv.Types; using Ryujinx.HLE.HOS.Services.Settings; @@ -16,6 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl private bool _isProductionMode; private NvHostSyncpt _syncpt; private NvHostEvent[] _events; + private KEvent _dummyEvent; public NvHostCtrlFileDevice(ServiceCtx context) : base(context) { @@ -28,8 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl _isProductionMode = true; } - _syncpt = new NvHostSyncpt(); - _events = new NvHostEvent[EventsCount]; + _syncpt = new NvHostSyncpt(); + _events = new NvHostEvent[EventsCount]; + _dummyEvent = new KEvent(context.Device.System); } public override NvInternalResult Ioctl(NvIoctl command, Span arguments) @@ -82,6 +86,28 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl return result; } + public override NvInternalResult QueryEvent(out int eventHandle, uint eventId) + { + // TODO: implement SyncPts <=> KEvent logic accurately. For now we return a dummy event. + KEvent targetEvent = _dummyEvent; + + if (targetEvent != null) + { + if (_owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + else + { + eventHandle = 0; + + return NvInternalResult.InvalidInput; + } + + return NvInternalResult.Success; + } + private NvInternalResult SyncptRead(ref NvFence arguments) { return SyncptReadMinOrMax(ref arguments, max: false); diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs index fac2f9394a..b70419f63b 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrlGpu/NvHostCtrlGpuFileDevice.cs @@ -1,5 +1,7 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types; using System; using System.Diagnostics; @@ -11,9 +13,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu private static Stopwatch _pTimer = new Stopwatch(); private static double _ticksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000; + private KEvent _errorEvent; + private KEvent _unknownEvent; + public NvHostCtrlGpuFileDevice(ServiceCtx context) : base(context) { - + _errorEvent = new KEvent(context.Device.System); + _unknownEvent = new KEvent(context.Device.System); } static NvHostCtrlGpuFileDevice() @@ -76,6 +82,38 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu return result; } + public override NvInternalResult QueryEvent(out int eventHandle, uint eventId) + { + // TODO: accurately represent and implement those events. + KEvent targetEvent = null; + + switch (eventId) + { + case 0x1: + targetEvent = _errorEvent; + break; + case 0x2: + targetEvent = _unknownEvent; + break; + } + + if (targetEvent != null) + { + if (_owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + } + else + { + eventHandle = 0; + + return NvInternalResult.InvalidInput; + } + + return NvInternalResult.Success; + } + public override void Close() { diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvQueryEventNotImplementedException.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvQueryEventNotImplementedException.cs new file mode 100644 index 0000000000..2af1574a6a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/Types/NvQueryEventNotImplementedException.cs @@ -0,0 +1,51 @@ +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Nv.Types +{ + class NvQueryEventlNotImplementedException : Exception + { + public ServiceCtx Context { get; } + public NvFileDevice FileDevice { get; } + public uint EventId { get; } + + public NvQueryEventlNotImplementedException(ServiceCtx context, NvFileDevice fileDevice, uint eventId) + : this(context, fileDevice, eventId, "The ioctl is not implemented.") + { } + + public NvQueryEventlNotImplementedException(ServiceCtx context, NvFileDevice fileDevice, uint eventId, string message) + : base(message) + { + Context = context; + FileDevice = fileDevice; + EventId = eventId; + } + + public override string Message + { + get + { + return base.Message + + Environment.NewLine + + Environment.NewLine + + BuildMessage(); + } + } + + private string BuildMessage() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendLine($"Device File: {FileDevice.GetType().Name}"); + sb.AppendLine(); + + sb.AppendLine($"Event ID: (0x{EventId:x8})"); + + sb.AppendLine("Guest Stack Trace:"); + sb.AppendLine(Context.Thread.GetGuestStackTrace()); + + return sb.ToString(); + } + } +}