mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-24 15:37:10 +02:00
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:
parent
461c24092a
commit
cf6cd71488
115 changed files with 2356 additions and 1088 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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+
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
}
|
||||
|
||||
Core.WaitDequeueEvent();
|
||||
|
||||
if (!Core.Active)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue