IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel (#1458)

* IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel

* Fix for applet transfer memory + some nits

* Keep handles if possible to avoid server handle table exhaustion

* Fix IPC ZeroFill bug

* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer

CreateManagedDisplaySeparableLayer is requires since 10.x+ when appletResourceUserId != 0

* Make it exit properly

* Make ServiceNotImplementedException show the full message again

* Allow yielding execution to avoid starving other threads

* Only wait if active

* Merge IVirtualMemoryManager and IAddressSpaceManager

* Fix Ro loading data from the wrong process

Co-authored-by: Thog <me@thog.eu>
This commit is contained in:
gdkchan 2020-12-01 20:23:43 -03:00 committed by GitHub
parent 461c24092a
commit cf6cd71488
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
115 changed files with 2356 additions and 1088 deletions

View file

@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
{
class ISystemAppletProxy : IpcService
{
public ISystemAppletProxy() { }
private readonly long _pid;
public ISystemAppletProxy(long pid)
{
_pid = pid;
}
[Command(0)]
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
@ -19,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
// GetSelfController() -> object<nn::am::service::ISelfController>
public ResultCode GetSelfController(ServiceCtx context)
{
MakeObject(context, new ISelfController(context.Device.System));
MakeObject(context, new ISelfController(context.Device.System, _pid));
return ResultCode.Success;
}
@ -28,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
// GetWindowController() -> object<nn::am::service::IWindowController>
public ResultCode GetWindowController(ServiceCtx context)
{
MakeObject(context, new IWindowController());
MakeObject(context, new IWindowController(_pid));
return ResultCode.Success;
}

View file

@ -18,6 +18,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
private KEvent _normalOutDataEvent;
private KEvent _interactiveOutDataEvent;
private int _stateChangedEventHandle;
private int _normalOutDataEventHandle;
private int _interactiveOutDataEventHandle;
public ILibraryAppletAccessor(AppletId appletId, Horizon system)
{
_stateChangedEvent = new KEvent(system.KernelContext);
@ -32,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
_applet.AppletStateChanged += OnAppletStateChanged;
_normalSession.DataAvailable += OnNormalOutData;
_interactiveSession.DataAvailable += OnInteractiveOutData;
Logger.Info?.Print(LogClass.ServiceAm, $"Applet '{appletId}' created.");
}
@ -55,12 +59,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// GetAppletStateChangedEvent() -> handle<copy>
public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_stateChangedEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangedEventHandle);
return ResultCode.Success;
}
@ -69,8 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// Start()
public ResultCode Start(ServiceCtx context)
{
return (ResultCode)_applet.Start(_normalSession.GetConsumer(),
_interactiveSession.GetConsumer());
return (ResultCode)_applet.Start(_normalSession.GetConsumer(), _interactiveSession.GetConsumer());
}
[Command(30)]
@ -138,12 +144,16 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// GetPopOutDataEvent() -> handle<copy>
public ResultCode GetPopOutDataEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_normalOutDataEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_normalOutDataEventHandle);
return ResultCode.Success;
}
@ -152,12 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// GetPopInteractiveOutDataEvent() -> handle<copy>
public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_interactiveOutDataEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_interactiveOutDataEventHandle);
return ResultCode.Success;
}

View file

@ -12,7 +12,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
private Apm.SystemManagerServer _apmSystemManagerServer;
private Lbl.LblControllerServer _lblControllerServer;
private bool _vrModeEnabled = false;
private bool _vrModeEnabled;
private int _messageEventHandle;
private int _displayResolutionChangedEventHandle;
public ICommonStateGetter(ServiceCtx context)
{
@ -25,14 +27,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// GetEventHandle() -> handle<copy>
public ResultCode GetEventHandle(ServiceCtx context)
{
KEvent Event = context.Device.System.AppletState.MessageEvent;
KEvent messageEvent = context.Device.System.AppletState.MessageEvent;
if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success)
if (_messageEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_messageEventHandle);
return ResultCode.Success;
}
@ -147,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
_lblControllerServer.DisableVrMode();
}
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
}
[Command(60)] // 3.0.0+
@ -164,12 +169,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_displayResolutionChangedEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_displayResolutionChangedEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
@ -189,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
_apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode);
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
return ResultCode.Success;
}

View file

@ -9,6 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
class IHomeMenuFunctions : IpcService
{
private KEvent _channelEvent;
private int _channelEventHandle;
public IHomeMenuFunctions(Horizon system)
{
@ -29,12 +30,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// GetPopFromGeneralChannelEvent() -> handle<copy>
public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_channelEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_channelEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm);

View file

@ -49,7 +49,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
}
var data = new byte[transferMem.Size];
context.Memory.Read(transferMem.Address, data);
transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
context.Device.System.KernelContext.Syscall.CloseHandle(handle);
MakeObject(context, new IStorage(data));

View file

@ -8,10 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
{
class ISelfController : IpcService
{
private readonly long _pid;
private KEvent _libraryAppletLaunchableEvent;
private int _libraryAppletLaunchableEventHandle;
private KEvent _accumulatedSuspendedTickChangedEvent;
private int _accumulatedSuspendedTickChangedEventHandle = 0;
private int _accumulatedSuspendedTickChangedEventHandle;
private object _fatalSectionLock = new object();
private int _fatalSectionCount;
@ -32,9 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
private uint _screenShotImageOrientation = 0;
private uint _idleTimeDetectionExtension = 0;
public ISelfController(Horizon system)
public ISelfController(Horizon system, long pid)
{
_libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
_pid = pid;
}
[Command(0)]
@ -103,12 +107,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
{
_libraryAppletLaunchableEvent.ReadableEvent.Signal();
if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_libraryAppletLaunchableEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_libraryAppletLaunchableEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm);
@ -206,6 +213,31 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.Success;
}
[Command(40)]
// CreateManagedDisplayLayer() -> u64
public ResultCode CreateManagedDisplayLayer(ServiceCtx context)
{
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long layerId);
context.ResponseData.Write(layerId);
return ResultCode.Success;
}
[Command(44)] // 10.0.0+
// CreateManagedDisplaySeparableLayer() -> (u64, u64)
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
{
// NOTE: first create the recoding layer and then the display one because right now Surface Flinger only use the last id.
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId);
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long displayLayerId);
context.ResponseData.Write(displayLayerId);
context.ResponseData.Write(recordingLayerId);
return ResultCode.Success;
}
[Command(50)]
// SetHandlesRequestToDisplay(b8)
public ResultCode SetHandlesRequestToDisplay(ServiceCtx context)

View file

@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
{
class IWindowController : IpcService
{
public IWindowController() { }
private readonly long _pid;
public IWindowController(long pid)
{
_pid = pid;
}
[Command(1)]
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
@ -12,7 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
{
Logger.Stub?.PrintStub(LogClass.ServiceAm);
context.ResponseData.Write(0L);
long appletResourceUserId = context.Device.System.AppletState.AppletResourceUserIds.Add(_pid);
context.ResponseData.Write(appletResourceUserId);
return ResultCode.Success;
}

View file

@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
// OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
public ResultCode OpenSystemAppletProxy(ServiceCtx context)
{
MakeObject(context, new ISystemAppletProxy());
MakeObject(context, new ISystemAppletProxy(context.Request.HandleDesc.PId));
return ResultCode.Success;
}

View file

@ -28,6 +28,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
private KEvent _friendInvitationStorageChannelEvent;
private KEvent _notificationStorageChannelEvent;
private int _gpuErrorDetectedSystemEventHandle;
private int _friendInvitationStorageChannelEventHandle;
private int _notificationStorageChannelEventHandle;
public IApplicationFunctions(Horizon system)
{
_gpuErrorDetectedSystemEvent = new KEvent(system.KernelContext);
@ -122,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
return ResultCode.Success;
}
// If desired language is not supported by application, use first supported language from TitleLanguage.
// If desired language is not supported by application, use first supported language from TitleLanguage.
// TODO: In the future, a GUI could enable user-specified search priority
if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
{
@ -293,12 +297,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height);
}
/*
if (transferMemoryHandle)
if (transferMemoryHandle != 0)
{
svcCloseHandle(transferMemoryHandle);
context.Device.System.KernelContext.Syscall.CloseHandle(transferMemoryHandle);
}
*/
return resultCode;
}
@ -455,15 +457,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetGpuErrorDetectedSystemEvent() -> handle<copy>
public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out int gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
if (_gpuErrorDetectedSystemEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(gpuErrorDetectedSystemEventHandle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_gpuErrorDetectedSystemEventHandle);
// NOTE: This is used by "sdk" NSO during applet-application initialization.
// A seperate thread is setup where event-waiting is handled.
// NOTE: This is used by "sdk" NSO during applet-application initialization.
// A seperate thread is setup where event-waiting is handled.
// When the Event is signaled, official sw will assert.
return ResultCode.Success;
@ -473,12 +478,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetFriendInvitationStorageChannelEvent() -> handle<copy>
public ResultCode GetFriendInvitationStorageChannelEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out int friendInvitationStorageChannelEventHandle) != KernelResult.Success)
if (_friendInvitationStorageChannelEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(friendInvitationStorageChannelEventHandle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_friendInvitationStorageChannelEventHandle);
return ResultCode.Success;
}
@ -501,12 +509,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetNotificationStorageChannelEvent() -> handle<copy>
public ResultCode GetNotificationStorageChannelEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out int notificationStorageChannelEventHandle) != KernelResult.Success)
if (_notificationStorageChannelEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(notificationStorageChannelEventHandle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationStorageChannelEventHandle);
return ResultCode.Success;
}

View file

@ -5,7 +5,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
{
class IApplicationProxy : IpcService
{
public IApplicationProxy() { }
private readonly long _pid;
public IApplicationProxy(long pid)
{
_pid = pid;
}
[Command(0)]
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
@ -20,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
// GetSelfController() -> object<nn::am::service::ISelfController>
public ResultCode GetSelfController(ServiceCtx context)
{
MakeObject(context, new ISelfController(context.Device.System));
MakeObject(context, new ISelfController(context.Device.System, _pid));
return ResultCode.Success;
}
@ -29,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
// GetWindowController() -> object<nn::am::service::IWindowController>
public ResultCode GetWindowController(ServiceCtx context)
{
MakeObject(context, new IWindowController());
MakeObject(context, new IWindowController(_pid));
return ResultCode.Success;
}

View file

@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
// OpenApplicationProxy(u64, pid, handle<copy>) -> object<nn::am::service::IApplicationProxy>
public ResultCode OpenApplicationProxy(ServiceCtx context)
{
MakeObject(context, new IApplicationProxy());
MakeObject(context, new IApplicationProxy(context.Request.HandleDesc.PId));
return ResultCode.Success;
}

View file

@ -10,15 +10,18 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
{
class IAudioOut : IpcService, IDisposable
{
private IAalOutput _audioOut;
private KEvent _releaseEvent;
private int _track;
private readonly IAalOutput _audioOut;
private readonly KEvent _releaseEvent;
private int _releaseEventHandle;
private readonly int _track;
private readonly int _clientHandle;
public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track)
public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track, int clientHandle)
{
_audioOut = audioOut;
_releaseEvent = releaseEvent;
_track = track;
_clientHandle = clientHandle;
}
[Command(0)]
@ -59,12 +62,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
// RegisterBufferEvent() -> handle<copy>
public ResultCode RegisterBufferEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_releaseEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out _releaseEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_releaseEventHandle);
return ResultCode.Success;
}
@ -108,7 +114,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
// NOTE: Assume PCM16 all the time, change if new format are found.
short[] buffer = new short[data.SampleBufferSize / sizeof(short)];
context.Memory.Read((ulong)data.SampleBufferPtr, MemoryMarshal.Cast<short, byte>(buffer));
context.Process.HandleTable.GetKProcess(_clientHandle).CpuMemory.Read((ulong)data.SampleBufferPtr, MemoryMarshal.Cast<short, byte>(buffer));
_audioOut.AppendBuffer(_track, tag, buffer);

View file

@ -33,7 +33,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
{
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, context.Memory, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
if (result == ResultCode.Success)
{

View file

@ -14,9 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
private IAudioRendererManager _impl;
public AudioRendererManagerServer(ServiceCtx context) : this(new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
public AudioRendererManagerServer(ServiceCtx context) : this(context, new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
public AudioRendererManagerServer(IAudioRendererManager impl) : base(new ServerBase("AudioRendererServer"))
public AudioRendererManagerServer(ServiceCtx context, IAudioRendererManager impl) : base(new ServerBase(context.Device.System.KernelContext, "AudioRendererServer"))
{
_impl = impl;
}
@ -40,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio
MakeObject(context, new AudioRendererServer(renderer));
}
context.Device.System.KernelContext.Syscall.CloseHandle((int)processHandle);
return result;
}

View file

@ -1,4 +1,5 @@
using Ryujinx.Cpu;
using Ryujinx.Memory;
using System;
using System.Text;
@ -57,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
return ResultCode.Success;
}
private uint ListAudioInsImpl(MemoryManager memory, long bufferPosition, long bufferSize, bool filtered = false)
private uint ListAudioInsImpl(IVirtualMemoryManager memory, long bufferPosition, long bufferSize, bool filtered = false)
{
uint count = 0;

View file

@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
private const int DefaultSampleRate = 48000;
private const int DefaultChannelsCount = 2;
public IAudioOutManager(ServiceCtx context) : base(new ServerBase("AudioOutServer")) { }
public IAudioOutManager(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "AudioOutServer")) { }
[Command(0)]
// ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
int track = audioOut.OpenTrack(sampleRate, channels, callback);
MakeObject(context, new IAudioOut(audioOut, releaseEvent, track));
MakeObject(context, new IAudioOut(audioOut, releaseEvent, track, context.Request.HandleDesc.ToCopy[0]));
context.ResponseData.Write(sampleRate);
context.ResponseData.Write(channels);

View file

@ -16,6 +16,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount));
// Close transfer memory immediately as we don't use it.
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
return ResultCode.Success;
}

View file

@ -12,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
class IDeliveryCacheProgressService : IpcService
{
private KEvent _event;
private int _eventHandle;
public IDeliveryCacheProgressService(ServiceCtx context)
{
@ -22,12 +23,15 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
// GetEvent() -> handle<copy>
public ResultCode GetEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
if (_eventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceBcat);

View file

@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
}
[Command(8)]
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
// -> object<nn::fssrv::sf::IFileSystem> contentFs
public ResultCode OpenFileSystemWithId(ServiceCtx context)
{
@ -138,12 +138,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID and owner ID if they're not already set
if (attribute.ProgramId == ProgramId.InvalidId)
{
attribute.ProgramId = new ProgramId(context.Process.TitleId);
}
if (creationInfo.OwnerId == 0)
{
creationInfo.OwnerId = 0;
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
}
Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}");
@ -215,12 +210,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID and owner ID if they're not already set
if (attribute.ProgramId == ProgramId.InvalidId)
{
attribute.ProgramId = new ProgramId(context.Process.TitleId);
}
if (creationInfo.OwnerId == 0)
{
creationInfo.OwnerId = 0;
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
}
Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt);
@ -239,7 +229,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID if it's not already set
if (attribute.ProgramId == ProgramId.InvalidId)
{
attribute.ProgramId = new ProgramId(context.Process.TitleId);
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
}
Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
@ -280,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID if it's not already set
if (attribute.ProgramId == ProgramId.InvalidId)
{
attribute.ProgramId = new ProgramId(context.Process.TitleId);
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
}
Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
@ -328,7 +318,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
filter.SetSaveDataType(SaveDataType.Cache);
filter.SetProgramId(new ProgramId(context.Process.TitleId));
// FS would query the User and SdCache space IDs to find where the existing cache is (if any).
// FS would query the User and SdCache space IDs to find where the existing cache is (if any).
// We always have the SD card inserted, so we can always use SdCache for now.
Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(
out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader, SaveDataSpaceId.SdCache);

View file

@ -8,6 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
class IAppletResource : IpcService
{
private KSharedMemory _hidSharedMem;
private int _hidSharedMemHandle;
public IAppletResource(KSharedMemory hidSharedMem)
{
@ -18,12 +19,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
// GetSharedMemoryHandle() -> handle<copy>
public ResultCode GetSharedMemoryHandle(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success)
if (_hidSharedMemHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_hidSharedMemHandle);
return ResultCode.Success;
}

View file

@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
private HidAccelerometerParameters _accelerometerParams;
private HidVibrationValue _vibrationValue;
public IHidServer(ServiceCtx context) : base(new ServerBase("HidServer"))
public IHidServer(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "HidServer"))
{
_xpadIdEvent = new KEvent(context.Device.System.KernelContext);
_palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);
@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
ControllerType type = (ControllerType)context.RequestData.ReadInt32();
long appletResourceUserId = context.RequestData.ReadInt64();
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
type
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
type
});
context.Device.Hid.Npads.SupportedStyleSets = type;
@ -577,9 +577,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
context.Device.Hid.Npads.SupportedStyleSets
context.Device.Hid.Npads.SupportedStyleSets
});
return ResultCode.Success;
@ -704,9 +704,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
long appletResourceUserId = context.RequestData.ReadInt64();
context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64();
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
context.Device.Hid.Npads.JoyHold
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
context.Device.Hid.Npads.JoyHold
});
return ResultCode.Success;
@ -720,9 +720,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold);
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
context.Device.Hid.Npads.JoyHold
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
appletResourceUserId,
context.Device.Hid.Npads.JoyHold
});
return ResultCode.Success;

View file

@ -1,8 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using System;
using System.Collections.Generic;
using System.IO;
@ -17,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services
public ServerBase Server { get; private set; }
private IpcService _parent;
private IdDictionary _domainObjects;
private int _selfId;
private bool _isDomain;
@ -32,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services
Server = server;
_parent = this;
_domainObjects = new IdDictionary();
_selfId = -1;
}
@ -62,8 +62,8 @@ namespace Ryujinx.HLE.HOS.Services
int domainWord0 = context.RequestData.ReadInt32();
int domainObjId = context.RequestData.ReadInt32();
int domainCmd = (domainWord0 >> 0) & 0xff;
int inputObjCount = (domainWord0 >> 8) & 0xff;
int domainCmd = (domainWord0 >> 0) & 0xff;
int inputObjCount = (domainWord0 >> 8) & 0xff;
int dataPayloadSize = (domainWord0 >> 16) & 0xffff;
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
@ -96,8 +96,8 @@ namespace Ryujinx.HLE.HOS.Services
}
}
long sfciMagic = context.RequestData.ReadInt64();
int commandId = (int)context.RequestData.ReadInt64();
long sfciMagic = context.RequestData.ReadInt64();
int commandId = (int)context.RequestData.ReadInt64();
bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest);
@ -145,56 +145,37 @@ namespace Ryujinx.HLE.HOS.Services
{
string dbgMessage = $"{service.GetType().FullName}: {commandId}";
throw new ServiceNotImplementedException(context, dbgMessage);
throw new ServiceNotImplementedException(service, context, dbgMessage);
}
}
protected static void MakeObject(ServiceCtx context, IpcService obj)
protected void MakeObject(ServiceCtx context, IpcService obj)
{
IpcService service = context.Session.Service;
obj.TrySetServer(_parent.Server);
obj.TrySetServer(service.Server);
if (service._isDomain)
if (_parent._isDomain)
{
context.Response.ObjectIds.Add(service.Add(obj));
obj._parent = _parent;
context.Response.ObjectIds.Add(_parent.Add(obj));
}
else
{
KSession session = new KSession(context.Device.System.KernelContext);
context.Device.System.KernelContext.Syscall.CreateSession(false, 0, out int serverSessionHandle, out int clientSessionHandle);
session.ClientSession.Service = obj;
obj.Server.AddSessionObj(serverSessionHandle, obj);
if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
session.ServerSession.DecrementReferenceCount();
session.ClientSession.DecrementReferenceCount();
context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeMove(clientSessionHandle);
}
}
protected static T GetObject<T>(ServiceCtx context, int index) where T : IpcService
protected T GetObject<T>(ServiceCtx context, int index) where T : IpcService
{
IpcService service = context.Session.Service;
if (!service._isDomain)
{
int handle = context.Request.HandleDesc.ToMove[index];
KClientSession session = context.Process.HandleTable.GetObject<KClientSession>(handle);
return session?.Service is T ? (T)session.Service : null;
}
int objId = context.Request.ObjectIds[index];
IIpcService obj = service.GetObject(objId);
IIpcService obj = _parent.GetObject(objId);
return obj is T ? (T)obj : null;
return obj is T t ? t : null;
}
public bool TrySetServer(ServerBase newServer)
@ -230,5 +211,10 @@ namespace Ryujinx.HLE.HOS.Services
{
return _domainObjects.GetData<IIpcService>(id);
}
public void SetParent(IpcService parent)
{
_parent = parent._parent;
}
}
}

View file

@ -103,98 +103,98 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
// StartDetection(bytes<8, 4>)
public ResultCode StartDetection(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(4)]
// StopDetection(bytes<8, 4>)
public ResultCode StopDetection(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(5)]
// Mount(bytes<8, 4>, u32, u32)
public ResultCode Mount(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(6)]
// Unmount(bytes<8, 4>)
public ResultCode Unmount(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(7)]
// OpenApplicationArea(bytes<8, 4>, u32)
public ResultCode OpenApplicationArea(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(8)]
// GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
public ResultCode GetApplicationArea(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(9)]
// SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
public ResultCode SetApplicationArea(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(10)]
// Flush(bytes<8, 4>)
public ResultCode Flush(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(11)]
// Restore(bytes<8, 4>)
public ResultCode Restore(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(12)]
// CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
public ResultCode CreateApplicationArea(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(13)]
// GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
public ResultCode GetTagInfo(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(14)]
// GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
public ResultCode GetRegisterInfo(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(15)]
// GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
public ResultCode GetCommonInfo(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(16)]
// GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
public ResultCode GetModelInfo(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(17)]
@ -308,7 +308,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
// GetApplicationAreaSize(bytes<8, 4>) -> u32
public ResultCode GetApplicationAreaSize(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(23)] // 3.0.0+
@ -334,7 +334,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
// RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
public ResultCode RecreateApplicationArea(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
}
}

View file

@ -11,6 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
private KEvent _event0;
private KEvent _event1;
private int _event0Handle;
private int _event1Handle;
private uint _version;
public IRequest(Horizon system, uint version)
@ -50,17 +53,23 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
// GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
public ResultCode GetSystemEventReadableHandles(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success)
if (_event0Handle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success)
if (_event1Handle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_event0Handle, _event1Handle);
return ResultCode.Success;
}
@ -107,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
return ResultCode.Unknown180;
}
// Returns appletId, libraryAppletMode, outSize and a buffer.
// Returns appletId, libraryAppletMode, outSize and a buffer.
// Returned applet ids- (0x19, 0xf, 0xe)
// libraryAppletMode seems to be 0 for all applets supported.

View file

@ -11,6 +11,8 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
{
private readonly KEvent _event;
private int _eventHandle;
public IShopServiceAccessor(Horizon system)
{
_event = new KEvent(system.KernelContext);
@ -22,12 +24,15 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
{
MakeObject(context, new IShopServiceAsync());
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
if (_eventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceNim);

View file

@ -9,7 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Ns
[Service("aoc:u")]
class IAddOnContentManager : IpcService
{
KEvent _addOnContentListChangedEvent;
private readonly KEvent _addOnContentListChangedEvent;
private int _addOnContentListChangedEventHandle;
public IAddOnContentManager(ServiceCtx context)
{
@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
{
long pid = context.Process.Pid;
// Official code checks ApplicationControlProperty.RuntimeAddOnContentInstall
// Official code checks ApplicationControlProperty.RuntimeAddOnContentInstall
// if true calls ns:am ListAvailableAddOnContent again to get updated count
byte runtimeAddOnContentInstall = context.Device.Application.ControlData.Value.RuntimeAddOnContentInstall;
@ -135,12 +137,15 @@ namespace Ryujinx.HLE.HOS.Services.Ns
{
// Official code seems to make an internal call to ns:am Cmd 84 GetDynamicCommitEvent()
if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_addOnContentListChangedEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_addOnContentListChangedEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceNs);
@ -148,7 +153,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
}
[Command(9)] // [10.0.0+]
[Command(9)] // [10.0.0+]
// GetAddOnContentLostErrorCode() -> u64
public ResultCode GetAddOnContentLostErrorCode(ServiceCtx context)
{

View file

@ -4,7 +4,6 @@ using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
@ -12,6 +11,7 @@ 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 Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Reflection;
@ -27,47 +27,45 @@ namespace Ryujinx.HLE.HOS.Services.Nv
private static Dictionary<string, Type> _deviceFileRegistry =
new Dictionary<string, Type>()
{
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
{ "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
{ "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) },
{ "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) },
//{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) },
{ "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) },
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
{ "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
{ "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) },
{ "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) },
//{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) },
{ "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) },
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
};
private static IdDictionary _deviceFileIdRegistry = new IdDictionary();
private KProcess _owner;
private IVirtualMemoryManager _clientMemory;
private long _owner;
private bool _transferMemInitialized = false;
public INvDrvServices(ServiceCtx context) : base(new ServerBase("NvservicesServer"))
public INvDrvServices(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "NvservicesServer"))
{
_owner = null;
_owner = 0;
}
private int Open(ServiceCtx context, string path)
{
if (context.Process == _owner)
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
{
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
{
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx) });
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(long) });
NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke(new object[] { context });
NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke(new object[] { context, _clientMemory, _owner });
deviceFile.Path = path;
deviceFile.Path = path;
return _deviceFileIdRegistry.Add(deviceFile);
}
else
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
}
return _deviceFileIdRegistry.Add(deviceFile);
}
else
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
}
return -1;
@ -150,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
return NvResult.NotImplemented;
}
if (deviceFile.Owner.Pid != _owner.Pid)
if (deviceFile.Owner != _owner)
{
return NvResult.AccessDenied;
}
@ -160,7 +158,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
private NvResult EnsureInitialized()
{
if (_owner == null)
if (_owner == 0)
{
Logger.Warning?.Print(LogClass.ServiceNv, "INvDrvServices is not initialized!");
@ -229,8 +227,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv
if (errorCode == NvResult.Success)
{
long pathPtr = context.Request.SendBuff[0].Position;
long pathSize = context.Request.SendBuff[0].Size;
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr);
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr, pathSize);
fd = Open(context, path);
@ -322,7 +321,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv
// TODO: When transfer memory will be implemented, this could be removed.
_transferMemInitialized = true;
_owner = context.Process;
int clientHandle = context.Request.HandleDesc.ToCopy[0];
_clientMemory = context.Process.HandleTable.GetKProcess(clientHandle).CpuMemory;
context.Device.System.KernelContext.Syscall.GetProcessId(clientHandle, out _owner);
context.ResponseData.Write((uint)NvResult.Success);
@ -425,7 +428,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
// ForceSetClientPid(u64) -> u32 error_code
public ResultCode ForceSetClientPid(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(8)]
@ -452,7 +455,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
// InitializeDevtools(u32, handle<copy>) -> u32 error_code;
public ResultCode InitializeDevtools(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(11)] // 3.0.0+

View file

@ -1,6 +1,5 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using System;
using System.Diagnostics;
using System.Reflection;
@ -12,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices
abstract class NvDeviceFile
{
public readonly ServiceCtx Context;
public readonly KProcess Owner;
public readonly long Owner;
public string Path;
public NvDeviceFile(ServiceCtx context)
public NvDeviceFile(ServiceCtx context, long owner)
{
Context = context;
Owner = context.Process;
Owner = owner;
}
public virtual NvInternalResult QueryEvent(out int eventHandle, uint eventId)

View file

@ -3,6 +3,7 @@ using Ryujinx.Graphics.Gpu.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 Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
@ -12,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
{
private static ConcurrentDictionary<KProcess, AddressSpaceContext> _addressSpaceContextRegistry = new ConcurrentDictionary<KProcess, AddressSpaceContext>();
public NvHostAsGpuDeviceFile(ServiceCtx context) : base(context) { }
public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner) { }
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
{

View file

@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using Ryujinx.HLE.HOS.Services.Nv.Types;
using Ryujinx.Memory;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -19,9 +20,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
private uint _submitTimeout;
private uint _timeslice;
private Switch _device;
private readonly Switch _device;
private Cpu.MemoryManager _memory;
private readonly IVirtualMemoryManager _memory;
public enum ResourcePolicy
{
@ -37,10 +38,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
private NvFence _channelSyncpoint;
public NvHostChannelDeviceFile(ServiceCtx context) : base(context)
public NvHostChannelDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
{
_device = context.Device;
_memory = context.Memory;
_memory = memory;
_timeout = 3000;
_submitTimeout = 0;
_timeslice = 0;

View file

@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
using Ryujinx.Memory;
using System;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
@ -11,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
private KEvent _smExceptionBptPauseReportEvent;
private KEvent _errorNotifierEvent;
public NvHostGpuDeviceFile(ServiceCtx context) : base(context)
public NvHostGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, memory, owner)
{
_smExceptionBptIntReportEvent = new KEvent(context.Device.System.KernelContext);
_smExceptionBptPauseReportEvent = new KEvent(context.Device.System.KernelContext);
@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
if (targetEvent != null)
{
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}

View file

@ -5,7 +5,7 @@ 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;
using Ryujinx.Memory;
using System;
using System.Text;
using System.Threading;
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
private Switch _device;
private NvHostEvent[] _events;
public NvHostCtrlDeviceFile(ServiceCtx context) : base(context)
public NvHostCtrlDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
{
if (NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting))
{
@ -126,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
if (targetEvent != null)
{
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}

View file

@ -2,6 +2,7 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
using Ryujinx.Memory;
using System;
using System.Diagnostics;
@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
private KEvent _errorEvent;
private KEvent _unknownEvent;
public NvHostCtrlGpuDeviceFile(ServiceCtx context) : base(context)
public NvHostCtrlGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
{
_errorEvent = new KEvent(context.Device.System.KernelContext);
_unknownEvent = new KEvent(context.Device.System.KernelContext);
@ -98,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
if (targetEvent != null)
{
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}

View file

@ -1,7 +1,7 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
@ -11,9 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
{
private const int FlagNotFreedYet = 1;
private static ConcurrentDictionary<KProcess, IdDictionary> _maps = new ConcurrentDictionary<KProcess, IdDictionary>();
private static ConcurrentDictionary<long, IdDictionary> _maps = new ConcurrentDictionary<long, IdDictionary>();
public NvMapDeviceFile(ServiceCtx context) : base(context)
public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
{
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
@ -244,9 +244,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
return dict.Add(map);
}
private static bool DeleteMapWithHandle(KProcess process, int handle)
private static bool DeleteMapWithHandle(long pid, int handle)
{
if (_maps.TryGetValue(process, out IdDictionary dict))
if (_maps.TryGetValue(pid, out IdDictionary dict))
{
return dict.Delete(handle) != null;
}
@ -254,14 +254,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
return false;
}
public static void IncrementMapRefCount(KProcess process, int handle, bool allowHandleZero = false)
public static void IncrementMapRefCount(long pid, int handle, bool allowHandleZero = false)
{
GetMapFromHandle(process, handle, allowHandleZero)?.IncrementRefCount();
GetMapFromHandle(pid, handle, allowHandleZero)?.IncrementRefCount();
}
public static bool DecrementMapRefCount(KProcess process, int handle)
public static bool DecrementMapRefCount(long pid, int handle)
{
NvMapHandle map = GetMapFromHandle(process, handle, false);
NvMapHandle map = GetMapFromHandle(pid, handle, false);
if (map == null)
{
@ -270,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
if (map.DecrementRefCount() <= 0)
{
DeleteMapWithHandle(process, handle);
DeleteMapWithHandle(pid, handle);
Logger.Info?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
@ -282,9 +282,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
}
}
public static NvMapHandle GetMapFromHandle(KProcess process, int handle, bool allowHandleZero = false)
public static NvMapHandle GetMapFromHandle(long pid, int handle, bool allowHandleZero = false)
{
if ((allowHandleZero || handle != 0) && _maps.TryGetValue(process, out IdDictionary dict))
if ((allowHandleZero || handle != 0) && _maps.TryGetValue(pid, out IdDictionary dict))
{
return dict.GetData<NvMapHandle>(handle);
}

View file

@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return ResultCode.InvalidAddress;
}
StructReader reader = new StructReader(context.Memory, nrrAddress);
StructReader reader = new StructReader(_owner.CpuMemory, nrrAddress);
NrrHeader header = reader.Read<NrrHeader>();
if (header.Magic != NrrMagic)
@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
{
byte[] temp = new byte[0x20];
context.Memory.Read((ulong)(nrrAddress + header.HashOffset + (i * 0x20)), temp);
_owner.CpuMemory.Read((ulong)(nrrAddress + header.HashOffset + (i * 0x20)), temp);
hashes.Add(temp);
}
@ -131,8 +131,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return ResultCode.InvalidAddress;
}
uint magic = context.Memory.Read<uint>(nroAddress + 0x10);
uint nroFileSize = context.Memory.Read<uint>(nroAddress + 0x18);
uint magic = _owner.CpuMemory.Read<uint>(nroAddress + 0x10);
uint nroFileSize = _owner.CpuMemory.Read<uint>(nroAddress + 0x18);
if (magic != NroMagic || nroSize != nroFileSize)
{
@ -141,7 +141,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
byte[] nroData = new byte[nroSize];
context.Memory.Read(nroAddress, nroData);
_owner.CpuMemory.Read(nroAddress, nroData);
byte[] nroHash = null;
@ -176,7 +176,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
// Check if everything is contiguous.
if (nro.RoOffset != nro.TextOffset + nro.Text.Length ||
nro.DataOffset != nro.RoOffset + nro.Ro.Length ||
nroFileSize != nro.DataOffset + nro.Data.Length)
nroFileSize != nro.DataOffset + nro.Data.Length)
{
return ResultCode.InvalidNro;
}
@ -337,21 +337,21 @@ namespace Ryujinx.HLE.HOS.Services.Ro
KernelResult result;
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, MemoryPermission.ReadAndExecute);
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, KMemoryPermission.ReadAndExecute);
if (result != KernelResult.Success)
{
return result;
}
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, MemoryPermission.Read);
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, KMemoryPermission.Read);
if (result != KernelResult.Success)
{
return result;
}
return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, MemoryPermission.ReadAndWrite);
return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, KMemoryPermission.ReadAndWrite);
}
private ResultCode RemoveNrrInfo(long nrrAddress)
@ -420,9 +420,9 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return (ResultCode)result;
}
private ResultCode IsInitialized(KProcess process)
private ResultCode IsInitialized(long pid)
{
if (_owner != null && _owner.Pid == process.Pid)
if (_owner != null && _owner.Pid == pid)
{
return ResultCode.Success;
}
@ -434,7 +434,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
// LoadNro(u64, u64, u64, u64, u64, pid) -> u64
public ResultCode LoadNro(ServiceCtx context)
{
ResultCode result = IsInitialized(context.Process);
ResultCode result = IsInitialized(_owner.Pid);
// Zero
context.RequestData.ReadUInt64();
@ -454,11 +454,11 @@ namespace Ryujinx.HLE.HOS.Services.Ro
if (result == ResultCode.Success)
{
result = MapNro(context.Process, info, out nroMappedAddress);
result = MapNro(_owner, info, out nroMappedAddress);
if (result == ResultCode.Success)
{
result = (ResultCode)SetNroMemoryPermissions(context.Process, info.Executable, nroMappedAddress);
result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress);
if (result == ResultCode.Success)
{
@ -479,7 +479,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
// UnloadNro(u64, u64, pid)
public ResultCode UnloadNro(ServiceCtx context)
{
ResultCode result = IsInitialized(context.Process);
ResultCode result = IsInitialized(_owner.Pid);
// Zero
context.RequestData.ReadUInt64();
@ -503,7 +503,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
// LoadNrr(u64, u64, u64, pid)
public ResultCode LoadNrr(ServiceCtx context)
{
ResultCode result = IsInitialized(context.Process);
ResultCode result = IsInitialized(_owner.Pid);
// pid placeholder, zero
context.RequestData.ReadUInt64();
@ -536,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
// UnloadNrr(u64, u64, pid)
public ResultCode UnloadNrr(ServiceCtx context)
{
ResultCode result = IsInitialized(context.Process);
ResultCode result = IsInitialized(_owner.Pid);
// pid placeholder, zero
context.RequestData.ReadUInt64();
@ -565,7 +565,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
return ResultCode.InvalidSession;
}
_owner = context.Process;
_owner = context.Process.HandleTable.GetKProcess(context.Request.HandleDesc.ToCopy[0]);
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
return ResultCode.Success;
}

View file

@ -9,6 +9,8 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
[Service("pl:s")] // 9.0.0+
class ISharedFontManager : IpcService
{
private int _fontSharedMemHandle;
public ISharedFontManager(ServiceCtx context) { }
[Command(0)]
@ -63,12 +65,15 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
{
context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager);
if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out int handle) != KernelResult.Success)
if (_fontSharedMemHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_fontSharedMemHandle);
return ResultCode.Success;
}

View file

@ -1,62 +1,193 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace Ryujinx.HLE.HOS.Services
{
class ServerBase
{
private struct IpcRequest
{
public Switch Device { get; }
public KProcess Process => Thread?.Owner;
public KThread Thread { get; }
public KClientSession Session { get; }
public ulong MessagePtr { get; }
public ulong MessageSize { get; }
// Must be the maximum value used by services (highest one know is the one used by nvservices = 0x8000).
// Having a size that is too low will cause failures as data copy will fail if the receiving buffer is
// not large enough.
private const int PointerBufferSize = 0x8000;
public IpcRequest(Switch device, KThread thread, KClientSession session, ulong messagePtr, ulong messageSize)
private readonly static int[] DefaultCapabilities = new int[]
{
0x030363F7,
0x1FFFFFCF,
0x207FFFEF,
0x47E0060F,
0x0048BFFF,
0x01007FFF
};
private readonly KernelContext _context;
private readonly KProcess _selfProcess;
private readonly List<int> _sessionHandles = new List<int>();
private readonly List<int> _portHandles = new List<int>();
private readonly Dictionary<int, IpcService> _sessions = new Dictionary<int, IpcService>();
private readonly Dictionary<int, IpcService> _ports = new Dictionary<int, IpcService>();
public ManualResetEvent InitDone { get; }
public IpcService SmObject { get; set; }
public string Name { get; }
public ServerBase(KernelContext context, string name)
{
InitDone = new ManualResetEvent(false);
Name = name;
_context = context;
const ProcessCreationFlags flags =
ProcessCreationFlags.EnableAslr |
ProcessCreationFlags.AddressSpace64Bit |
ProcessCreationFlags.Is64Bit |
ProcessCreationFlags.PoolPartitionSystem;
ProcessCreationInfo creationInfo = new ProcessCreationInfo("Service", 1, 0, 0x8000000, 1, flags, 0, 0);
context.Syscall.CreateProcess(creationInfo, DefaultCapabilities, out int handle, null, ServerLoop);
_selfProcess = context.Scheduler.GetCurrentProcess().HandleTable.GetKProcess(handle);
context.Syscall.StartProcess(handle, 44, 3, 0x1000);
}
private void AddPort(int serverPortHandle, IpcService obj)
{
_portHandles.Add(serverPortHandle);
_ports.Add(serverPortHandle, obj);
}
public void AddSessionObj(KServerSession serverSession, IpcService obj)
{
_selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle);
AddSessionObj(serverSessionHandle, obj);
}
public void AddSessionObj(int serverSessionHandle, IpcService obj)
{
_sessionHandles.Add(serverSessionHandle);
_sessions.Add(serverSessionHandle, obj);
}
private void ServerLoop()
{
if (SmObject != null)
{
Device = device;
Thread = thread;
Session = session;
MessagePtr = messagePtr;
MessageSize = messageSize;
_context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle);
AddPort(serverPortHandle, SmObject);
InitDone.Set();
}
else
{
InitDone.Dispose();
}
public void SignalDone(KernelResult result)
KThread thread = _context.Scheduler.GetCurrentThread();
ulong messagePtr = thread.TlsAddress;
_context.Syscall.SetHeapSize(0x200000, out ulong heapAddr);
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
_selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
int replyTargetHandle = 0;
while (true)
{
Thread.ObjSyncResult = result;
Thread.Reschedule(ThreadSchedState.Running);
int[] handles = _portHandles.ToArray();
for (int i = 0; i < handles.Length; i++)
{
if (_context.Syscall.AcceptSession(handles[i], out int serverSessionHandle) == KernelResult.Success)
{
AddSessionObj(serverSessionHandle, _ports[handles[i]]);
}
}
handles = _sessionHandles.ToArray();
var rc = _context.Syscall.ReplyAndReceive(handles, replyTargetHandle, 1000000L, out int signaledIndex);
thread.HandlePostSyscall();
if (!thread.Context.Running)
{
break;
}
replyTargetHandle = 0;
if (rc == KernelResult.Success && signaledIndex != -1)
{
int signaledHandle = handles[signaledIndex];
if (Process(signaledHandle, heapAddr))
{
replyTargetHandle = signaledHandle;
}
}
else
{
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
_selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
}
}
}
private readonly AsyncWorkQueue<IpcRequest> _ipcProcessor;
public ServerBase(string name)
private bool Process(int serverSessionHandle, ulong recvListAddr)
{
_ipcProcessor = new AsyncWorkQueue<IpcRequest>(Process, name);
}
KProcess process = _context.Scheduler.GetCurrentProcess();
KThread thread = _context.Scheduler.GetCurrentThread();
ulong messagePtr = thread.TlsAddress;
ulong messageSize = 0x100;
public void PushMessage(Switch device, KThread thread, KClientSession session, ulong messagePtr, ulong messageSize)
{
_ipcProcessor.Add(new IpcRequest(device, thread, session, messagePtr, messageSize));
}
byte[] reqData = new byte[messageSize];
private void Process(IpcRequest message)
{
byte[] reqData = new byte[message.MessageSize];
process.CpuMemory.Read(messagePtr, reqData);
message.Process.CpuMemory.Read(message.MessagePtr, reqData);
IpcMessage request = new IpcMessage(reqData, (long)message.MessagePtr);
IpcMessage request = new IpcMessage(reqData, (long)messagePtr);
IpcMessage response = new IpcMessage();
ulong tempAddr = recvListAddr;
int sizesOffset = request.RawData.Length - ((request.RecvListBuff.Count * 2 + 3) & ~3);
bool noReceive = true;
for (int i = 0; i < request.ReceiveBuff.Count; i++)
{
noReceive &= (request.ReceiveBuff[i].Position == 0);
}
if (noReceive)
{
for (int i = 0; i < request.RecvListBuff.Count; i++)
{
int size = BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan().Slice(sizesOffset + i * 2, 2));
response.PtrBuff.Add(new IpcPtrBuffDesc((long)tempAddr, i, size));
request.RecvListBuff[i] = new IpcRecvListBuffDesc((long)tempAddr, size);
tempAddr += (ulong)size;
}
}
bool shouldReply = true;
using (MemoryStream raw = new MemoryStream(request.RawData))
{
BinaryReader reqReader = new BinaryReader(raw);
@ -71,17 +202,16 @@ namespace Ryujinx.HLE.HOS.Services
BinaryWriter resWriter = new BinaryWriter(resMs);
ServiceCtx context = new ServiceCtx(
message.Device,
message.Process,
message.Process.CpuMemory,
message.Thread,
message.Session,
_context.Device,
process,
process.CpuMemory,
thread,
request,
response,
reqReader,
resWriter);
message.Session.Service.CallMethod(context);
_sessions[serverSessionHandle].CallMethod(context);
response.RawData = resMs.ToArray();
}
@ -95,11 +225,11 @@ namespace Ryujinx.HLE.HOS.Services
switch (cmdId)
{
case 0:
request = FillResponse(response, 0, message.Session.Service.ConvertToDomain());
request = FillResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain());
break;
case 3:
request = FillResponse(response, 0, 0x1000);
request = FillResponse(response, 0, PointerBufferSize);
break;
// TODO: Whats the difference between IpcDuplicateSession/Ex?
@ -107,12 +237,11 @@ namespace Ryujinx.HLE.HOS.Services
case 4:
int unknown = reqReader.ReadInt32();
if (message.Process.HandleTable.GenerateHandle(message.Session, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
_context.Syscall.CreateSession(false, 0, out int dupServerSessionHandle, out int dupClientSessionHandle);
response.HandleDesc = IpcHandleDesc.MakeMove(handle);
AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]);
response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle);
request = FillResponse(response, 0);
@ -123,18 +252,24 @@ namespace Ryujinx.HLE.HOS.Services
}
else if (request.Type == IpcMessageType.CloseSession)
{
message.SignalDone(KernelResult.PortRemoteClosed);
return;
_context.Syscall.CloseHandle(serverSessionHandle);
_sessionHandles.Remove(serverSessionHandle);
IpcService service = _sessions[serverSessionHandle];
if (service is IDisposable disposableObj)
{
disposableObj.Dispose();
}
_sessions.Remove(serverSessionHandle);
shouldReply = false;
}
else
{
throw new NotImplementedException(request.Type.ToString());
}
message.Process.CpuMemory.Write(message.MessagePtr, response.GetBytes((long)message.MessagePtr));
process.CpuMemory.Write(messagePtr, response.GetBytes((long)messagePtr, recvListAddr | ((ulong)PointerBufferSize << 48)));
return shouldReply;
}
message.SignalDone(KernelResult.Success);
}
private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)

View file

@ -1,5 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using System;
@ -11,18 +12,17 @@ using System.Reflection;
namespace Ryujinx.HLE.HOS.Services.Sm
{
[Service("sm:")]
class IUserInterface : IpcService
{
private Dictionary<string, Type> _services;
private ConcurrentDictionary<string, KPort> _registeredServices;
private readonly ConcurrentDictionary<string, KPort> _registeredServices;
private readonly ServerBase _commonServer;
private bool _isInitialized;
public IUserInterface(ServiceCtx context = null) : base(new ServerBase("SmServer"))
public IUserInterface(KernelContext context)
{
_registeredServices = new ConcurrentDictionary<string, KPort>();
@ -31,18 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.Sm
.Select(service => (((ServiceAttribute)service).Name, type)))
.ToDictionary(service => service.Name, service => service.type);
_commonServer = new ServerBase("CommonServer");
}
TrySetServer(new ServerBase(context, "SmServer") { SmObject = this });
public static void InitializePort(Horizon system)
{
KPort port = new KPort(system.KernelContext, 256, false, 0);
port.ClientPort.SetName("sm:");
IUserInterface smService = new IUserInterface();
port.ClientPort.Service = smService;
_commonServer = new ServerBase(context, "CommonServer");
}
[Command(0)]
@ -92,16 +83,13 @@ namespace Ryujinx.HLE.HOS.Services.Sm
: (IpcService)Activator.CreateInstance(type, context);
service.TrySetServer(_commonServer);
session.ClientSession.Service = service;
service.Server.AddSessionObj(session.ServerSession, service);
}
else
{
if (ServiceConfiguration.IgnoreMissingServices)
{
Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
session.ClientSession.Service = new DummyService(name);
}
else
{
@ -142,7 +130,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
int maxSessions = context.RequestData.ReadInt32();
if (name == string.Empty)
if (string.IsNullOrEmpty(name))
{
return ResultCode.InvalidName;
}
@ -185,7 +173,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
int maxSessions = context.RequestData.ReadInt32();
if (name == string.Empty)
if (string.IsNullOrEmpty(name))
{
return ResultCode.InvalidName;
}

View file

@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
private List<BsdSocket> _sockets = new List<BsdSocket>();
public IClient(ServiceCtx context, bool isPrivileged) : base(new ServerBase("BsdServer"))
public IClient(ServiceCtx context, bool isPrivileged) : base(new ServerBase(context.Device.System.KernelContext, "BsdServer"))
{
_isPrivileged = isPrivileged;
}
@ -247,6 +247,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
Logger.Stub?.PrintStub(LogClass.ServiceBsd);
// Close transfer memory immediately as we don't use it.
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
return ResultCode.Success;
}

View file

@ -118,14 +118,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
// ImportSettings(u32, buffer<unknown, 5>) -> buffer<unknown, 6>
public ResultCode ImportSettings(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(15)]
// Unknown(bytes<1>)
public ResultCode Unknown(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(20)]
@ -164,49 +164,49 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
// GetNasServiceSetting(buffer<unknown<0x10>, 0x15>) -> buffer<unknown<0x108>, 0x16>
public ResultCode GetNasServiceSetting(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(31)]
// GetNasServiceSettingEx(buffer<unknown<0x10>, 0x15>) -> (u32, buffer<unknown<0x108>, 0x16>)
public ResultCode GetNasServiceSettingEx(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(40)]
// GetNasRequestFqdn() -> buffer<unknown<0x100>, 0x16>
public ResultCode GetNasRequestFqdn(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(41)]
// GetNasRequestFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
public ResultCode GetNasRequestFqdnEx(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(42)]
// GetNasApiFqdn() -> buffer<unknown<0x100>, 0x16>
public ResultCode GetNasApiFqdn(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(43)]
// GetNasApiFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
public ResultCode GetNasApiFqdnEx(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(50)]
// GetCurrentSetting() -> buffer<unknown<0x12bf0>, 0x16>
public ResultCode GetCurrentSetting(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(60)]
@ -262,7 +262,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
// IsChangeEnvironmentIdentifierDisabled() -> bytes<1>
public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context)
{
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
}
}

View file

@ -1,15 +1,15 @@
using Ryujinx.HLE.HOS.Kernel.Process;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
class BufferQueue
static class BufferQueue
{
public static void CreateBufferQueue(Switch device, KProcess process, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
public static BufferQueueCore CreateBufferQueue(Switch device, long pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
{
BufferQueueCore core = new BufferQueueCore(device, process);
BufferQueueCore core = new BufferQueueCore(device, pid);
producer = new BufferQueueProducer(core);
consumer = new BufferQueueConsumer(core);
return core;
}
}
}

View file

@ -1,5 +1,5 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
using System;
@ -40,11 +40,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
private KEvent _waitBufferFreeEvent;
private KEvent _frameAvailableEvent;
public KProcess Owner { get; }
public long Owner { get; }
public bool Active { get; private set; }
public const int BufferHistoryArraySize = 8;
public BufferQueueCore(Switch device, KProcess process)
public BufferQueueCore(Switch device, long pid)
{
Slots = new BufferSlotArray();
IsAbandoned = false;
@ -70,7 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
_waitBufferFreeEvent = new KEvent(device.System.KernelContext);
_frameAvailableEvent = new KEvent(device.System.KernelContext);
Owner = process;
Owner = pid;
Active = true;
BufferHistory = new BufferInfo[BufferHistoryArraySize];
EnableExternalEvent = true;
@ -162,6 +166,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
public void PrepareForExit()
{
lock (Lock)
{
Active = false;
Monitor.PulseAll(Lock);
}
}
// TODO: Find an accurate way to handle a regular condvar here as this will wake up unwanted threads in some edge cases.
public void SignalDequeueEvent()
{
@ -170,7 +184,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void WaitDequeueEvent()
{
Monitor.Wait(Lock);
Monitor.Exit(Lock);
KernelStatic.YieldUntilCompletion(WaitForLock);
Monitor.Enter(Lock);
}
public void SignalIsAllocatingEvent()
@ -180,7 +198,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void WaitIsAllocatingEvent()
{
Monitor.Wait(Lock);
Monitor.Exit(Lock);
KernelStatic.YieldUntilCompletion(WaitForLock);
Monitor.Enter(Lock);
}
private void WaitForLock()
{
lock (Lock)
{
if (Active)
{
Monitor.Wait(Lock);
}
}
}
public void FreeBufferLocked(int slot)

View file

@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
Core.WaitDequeueEvent();
if (!Core.Active)
{
break;
}
}
}

View file

@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
abstract class IHOSBinderDriver : IpcService
{
public IHOSBinderDriver() {}
public IHOSBinderDriver() { }
[Command(0)]
// TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>

View file

@ -1,10 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -40,7 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public int ProducerBinderId;
public IGraphicBufferProducer Producer;
public BufferItemConsumer Consumer;
public KProcess Owner;
public BufferQueueCore Core;
public long Owner;
}
private class TextureCallbackInformation
@ -84,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
public IGraphicBufferProducer OpenLayer(KProcess process, long layerId)
public IGraphicBufferProducer OpenLayer(long pid, long layerId)
{
bool needCreate;
@ -95,13 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
if (needCreate)
{
CreateLayerFromId(process, layerId);
CreateLayerFromId(pid, layerId);
}
return GetProducerByLayerId(layerId);
}
public IGraphicBufferProducer CreateLayer(KProcess process, out long layerId)
public IGraphicBufferProducer CreateLayer(long pid, out long layerId)
{
layerId = 1;
@ -116,25 +114,26 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
CreateLayerFromId(process, layerId);
CreateLayerFromId(pid, layerId);
return GetProducerByLayerId(layerId);
}
private void CreateLayerFromId(KProcess process, long layerId)
private void CreateLayerFromId(long pid, long layerId)
{
lock (Lock)
{
Logger.Info?.Print(LogClass.SurfaceFlinger, $"Creating layer {layerId}");
BufferQueue.CreateBufferQueue(_device, process, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
BufferQueueCore core = BufferQueue.CreateBufferQueue(_device, pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
_layers.Add(layerId, new Layer
{
ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
Producer = producer,
Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
Owner = process
Core = core,
Owner = pid
});
LastId = layerId;
@ -345,6 +344,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void Dispose()
{
_isRunning = false;
foreach (Layer layer in _layers.Values)
{
layer.Core.PrepareForExit();
}
}
public void OnFrameAvailable(ref BufferItem item)

View file

@ -42,23 +42,23 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Buffer = parcel.ReadUnmanagedType<NvGraphicBuffer>();
}
public void IncrementNvMapHandleRefCount(KProcess process)
public void IncrementNvMapHandleRefCount(long pid)
{
NvMapDeviceFile.IncrementMapRefCount(process, Buffer.NvMapId);
NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.NvMapId);
for (int i = 0; i < Buffer.Surfaces.Length; i++)
{
NvMapDeviceFile.IncrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
}
}
public void DecrementNvMapHandleRefCount(KProcess process)
public void DecrementNvMapHandleRefCount(long pid)
{
NvMapDeviceFile.DecrementMapRefCount(process, Buffer.NvMapId);
NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.NvMapId);
for (int i = 0; i < Buffer.Surfaces.Length; i++)
{
NvMapDeviceFile.DecrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
}
}

View file

@ -15,10 +15,12 @@ namespace Ryujinx.HLE.HOS.Services.Time
private IStaticServiceForPsc _inner;
private TimePermissions _permissions;
public IStaticServiceForGlue(ServiceCtx context, TimePermissions permissions) : base(new ServerBase("TimeServer"))
public IStaticServiceForGlue(ServiceCtx context, TimePermissions permissions) : base(new ServerBase(context.Device.System.KernelContext, "TimeServer"))
{
_permissions = permissions;
_inner = new IStaticServiceForPsc(context, permissions);
_inner.TrySetServer(Server);
_inner.SetParent(this);
}
[Command(0)]

View file

@ -149,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public ResultCode Unknown50(ServiceCtx context)
{
// TODO: figure out the usage of this event
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(51)]
@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public ResultCode Unknown51(ServiceCtx context)
{
// TODO: figure out the usage of this event
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(52)]
@ -165,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public ResultCode Unknown52(ServiceCtx context)
{
// TODO: figure out the usage of this event
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(60)]
@ -201,7 +201,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public ResultCode GetAlarmRegistrationEvent(ServiceCtx context)
{
// TODO
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(201)]
@ -209,7 +209,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public ResultCode UpdateSteadyAlarms(ServiceCtx context)
{
// TODO
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
[Command(202)]
@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public ResultCode TryGetNextSteadyClockAlarmSnapshot(ServiceCtx context)
{
// TODO
throw new ServiceNotImplementedException(context);
throw new ServiceNotImplementedException(this, context);
}
}
}

View file

@ -5,8 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
[Service("vi:u")]
class IApplicationRootService : IpcService
{
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
public IApplicationRootService(ServiceCtx context) : base(new ServerBase("ViServerU")) { }
public IApplicationRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerU")) { }
[Command(0)]
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>

View file

@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
class IManagerRootService : IpcService
{
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
public IManagerRootService(ServiceCtx context) : base(new ServerBase("ViServerM")) { }
public IManagerRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerM")) { }
[Command(2)]
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>

View file

@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
class ISystemRootService : IpcService
{
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
public ISystemRootService(ServiceCtx context) : base(new ServerBase("ViServerS")) { }
public ISystemRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerS")) { }
[Command(1)]
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>

View file

@ -1,11 +1,10 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
{
class IManagerDisplayService : IpcService
{
private static IApplicationDisplayService _applicationDisplayService;
private IApplicationDisplayService _applicationDisplayService;
public IManagerDisplayService(IApplicationDisplayService applicationDisplayService)
{
@ -16,10 +15,13 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
// CreateManagedLayer(u32, u64, nn::applet::AppletResourceUserId) -> u64
public ResultCode CreateManagedLayer(ServiceCtx context)
{
long layerFlags = context.RequestData.ReadInt64();
long displayId = context.RequestData.ReadInt64();
long layerFlags = context.RequestData.ReadInt64();
long displayId = context.RequestData.ReadInt64();
long appletResourceUserId = context.RequestData.ReadInt64();
context.Device.System.SurfaceFlinger.CreateLayer(context.Process, out long layerId);
long pid = context.Device.System.AppletState.AppletResourceUserIds.GetData<long>((int)appletResourceUserId);
context.Device.System.SurfaceFlinger.CreateLayer(pid, out long layerId);
context.ResponseData.Write(layerId);

View file

@ -4,7 +4,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
{
class ISystemDisplayService : IpcService
{
private static IApplicationDisplayService _applicationDisplayService;
private IApplicationDisplayService _applicationDisplayService;
public ISystemDisplayService(IApplicationDisplayService applicationDisplayService)
{

View file

@ -11,7 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{
class IApplicationDisplayService : IpcService
{
private IdDictionary _displays;
private readonly IdDictionary _displays;
private int _vsyncEventHandle;
public IApplicationDisplayService()
{
@ -121,7 +123,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
long userId = context.RequestData.ReadInt64();
long parcelPtr = context.Request.ReceiveBuff[0].Position;
IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Process, layerId);
IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId);
Parcel parcel = new Parcel(0x28, 0x4);
@ -159,7 +161,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
// TODO: support multi display.
Display disp = _displays.GetData<Display>((int)displayId);
IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(context.Process, out long layerId);
IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(0, out long layerId);
Parcel parcel = new Parcel(0x28, 0x4);
@ -268,8 +270,8 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
const ulong defaultAlignment = 0x1000;
const ulong defaultSize = 0x20000;
// NOTE: The official service setup a A8B8G8R8 texture with a linear layout and then query its size.
// As we don't need this texture on the emulator, we can just simplify this logic and directly
// NOTE: The official service setup a A8B8G8R8 texture with a linear layout and then query its size.
// As we don't need this texture on the emulator, we can just simplify this logic and directly
// do a linear layout size calculation. (stride * height * bytePerPixel)
int pitch = BitUtils.AlignUp(BitUtils.DivRoundUp(width * 32, 8), 64);
int memorySize = pitch * BitUtils.AlignUp(height, 64);
@ -289,12 +291,15 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{
string name = GetDisplayName(context);
if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out int handle) != KernelResult.Success)
if (_vsyncEventHandle == 0)
{
throw new InvalidOperationException("Out of handles!");
if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out _vsyncEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_vsyncEventHandle);
return ResultCode.Success;
}