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
|
@ -66,7 +66,7 @@ namespace ARMeilleure.State
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool Running { get; private set; }
|
public bool Running { get; private set; }
|
||||||
|
|
||||||
public event EventHandler<EventArgs> Interrupt;
|
public event EventHandler<EventArgs> Interrupt;
|
||||||
public event EventHandler<InstExceptionEventArgs> Break;
|
public event EventHandler<InstExceptionEventArgs> Break;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
using Ryujinx.Audio.Renderer.Common;
|
using Ryujinx.Audio.Renderer.Common;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -65,7 +65,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
IsEffectEnabled = isEnabled;
|
IsEffectEnabled = isEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint Read(MemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount)
|
private uint Read(IVirtualMemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount)
|
||||||
{
|
{
|
||||||
if (countMax == 0 || bufferAddress == 0)
|
if (countMax == 0 || bufferAddress == 0)
|
||||||
{
|
{
|
||||||
|
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint Write(MemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount)
|
private uint Write(IVirtualMemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount)
|
||||||
{
|
{
|
||||||
if (countMax == 0 || outBufferAddress == 0)
|
if (countMax == 0 || outBufferAddress == 0)
|
||||||
{
|
{
|
||||||
|
@ -175,8 +175,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
ZeroFill(context.MemoryManager, BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
||||||
MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
ZeroFill(context.MemoryManager, BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
||||||
|
|
||||||
if (InputBufferIndex != OutputBufferIndex)
|
if (InputBufferIndex != OutputBufferIndex)
|
||||||
{
|
{
|
||||||
|
@ -184,5 +184,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ZeroFill(IVirtualMemoryManager memoryManager, ulong address, int size)
|
||||||
|
{
|
||||||
|
ulong endAddress = address + (ulong)size;
|
||||||
|
|
||||||
|
while (address + 7UL < endAddress)
|
||||||
|
{
|
||||||
|
memoryManager.Write(address, 0UL);
|
||||||
|
address += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (address < endAddress)
|
||||||
|
{
|
||||||
|
memoryManager.Write(address, (byte)0);
|
||||||
|
address++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Integration;
|
||||||
using Ryujinx.Audio.Renderer.Server;
|
using Ryujinx.Audio.Renderer.Server;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
public List<ICommand> Commands { get; }
|
public List<ICommand> Commands { get; }
|
||||||
|
|
||||||
public MemoryManager MemoryManager { get; }
|
public IVirtualMemoryManager MemoryManager { get; }
|
||||||
|
|
||||||
public HardwareDevice OutputDevice { get; private set; }
|
public HardwareDevice OutputDevice { get; private set; }
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandList(MemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax)
|
public CommandList(IVirtualMemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax)
|
||||||
{
|
{
|
||||||
SampleCount = sampleCount;
|
SampleCount = sampleCount;
|
||||||
SampleRate = sampleRate;
|
SampleRate = sampleRate;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
using Ryujinx.Audio.Renderer.Common;
|
using Ryujinx.Audio.Renderer.Common;
|
||||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -63,7 +63,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ProcessWaveBuffers(MemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount)
|
public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount)
|
||||||
{
|
{
|
||||||
const int tempBufferSize = 0x3F00;
|
const int tempBufferSize = 0x3F00;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
|
@ -33,22 +33,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||||
public uint WriteOffset;
|
public uint WriteOffset;
|
||||||
private uint _reserved;
|
private uint _reserved;
|
||||||
|
|
||||||
public static uint GetReadOffset(MemoryManager manager, ulong bufferAddress)
|
public static uint GetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress)
|
||||||
{
|
{
|
||||||
return manager.Read<uint>(bufferAddress + ReadOffsetPosition);
|
return manager.Read<uint>(bufferAddress + ReadOffsetPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint GetWriteOffset(MemoryManager manager, ulong bufferAddress)
|
public static uint GetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress)
|
||||||
{
|
{
|
||||||
return manager.Read<uint>(bufferAddress + WriteOffsetPosition);
|
return manager.Read<uint>(bufferAddress + WriteOffsetPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetReadOffset(MemoryManager manager, ulong bufferAddress, uint value)
|
public static void SetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value)
|
||||||
{
|
{
|
||||||
manager.Write(bufferAddress + ReadOffsetPosition, value);
|
manager.Write(bufferAddress + ReadOffsetPosition, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetWriteOffset(MemoryManager manager, ulong bufferAddress, uint value)
|
public static void SetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value)
|
||||||
{
|
{
|
||||||
manager.Write(bufferAddress + WriteOffsetPosition, value);
|
manager.Write(bufferAddress + WriteOffsetPosition, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
|
<ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -31,7 +31,7 @@ using Ryujinx.Audio.Renderer.Server.Voice;
|
||||||
using Ryujinx.Audio.Renderer.Utils;
|
using Ryujinx.Audio.Renderer.Utils;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -87,7 +87,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
private Memory<byte> _performanceBuffer;
|
private Memory<byte> _performanceBuffer;
|
||||||
|
|
||||||
public MemoryManager MemoryManager { get; private set; }
|
public IVirtualMemoryManager MemoryManager { get; private set; }
|
||||||
|
|
||||||
private ulong _elapsedFrameCount;
|
private ulong _elapsedFrameCount;
|
||||||
private ulong _renderingStartTick;
|
private ulong _renderingStartTick;
|
||||||
|
@ -96,14 +96,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
|
|
||||||
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
|
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_terminationEvent = new ManualResetEvent(false);
|
_terminationEvent = new ManualResetEvent(false);
|
||||||
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||||
_voiceContext = new VoiceContext();
|
_voiceContext = new VoiceContext();
|
||||||
_mixContext = new MixContext();
|
_mixContext = new MixContext();
|
||||||
_sinkContext = new SinkContext();
|
_sinkContext = new SinkContext();
|
||||||
_splitterContext = new SplitterContext();
|
_splitterContext = new SplitterContext();
|
||||||
_effectContext = new EffectContext();
|
_effectContext = new EffectContext();
|
||||||
|
|
||||||
_commandProcessingTimeEstimator = null;
|
_commandProcessingTimeEstimator = null;
|
||||||
_systemEvent = systemEvent;
|
_systemEvent = systemEvent;
|
||||||
|
@ -113,7 +113,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
_sessionId = 0;
|
_sessionId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, MemoryManager memoryManager)
|
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
|
||||||
{
|
{
|
||||||
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Dsp;
|
||||||
using Ryujinx.Audio.Renderer.Integration;
|
using Ryujinx.Audio.Renderer.Integration;
|
||||||
using Ryujinx.Audio.Renderer.Parameter;
|
using Ryujinx.Audio.Renderer.Parameter;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -288,7 +288,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
/// <param name="workBufferSize">The guest work buffer size.</param>
|
/// <param name="workBufferSize">The guest work buffer size.</param>
|
||||||
/// <param name="processHandle">The process handle of the application.</param>
|
/// <param name="processHandle">The process handle of the application.</param>
|
||||||
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
|
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
|
||||||
public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, MemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle)
|
public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle)
|
||||||
{
|
{
|
||||||
int sessionId = AcquireSessionId();
|
int sessionId = AcquireSessionId();
|
||||||
|
|
||||||
|
@ -321,6 +321,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
|
lock (_audioProcessorLock)
|
||||||
|
{
|
||||||
|
if (_isRunning)
|
||||||
|
{
|
||||||
|
StopLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Processor.Dispose();
|
Processor.Dispose();
|
||||||
|
|
||||||
foreach (HardwareDevice device in OutputDevices)
|
foreach (HardwareDevice device in OutputDevices)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -7,7 +8,7 @@ namespace Ryujinx.Cpu
|
||||||
{
|
{
|
||||||
public static class MemoryHelper
|
public static class MemoryHelper
|
||||||
{
|
{
|
||||||
public static void FillWithZeros(MemoryManager memory, long position, int size)
|
public static void FillWithZeros(IVirtualMemoryManager memory, long position, int size)
|
||||||
{
|
{
|
||||||
int size8 = size & ~(8 - 1);
|
int size8 = size & ~(8 - 1);
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ namespace Ryujinx.Cpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static T Read<T>(MemoryManager memory, long position) where T : struct
|
public unsafe static T Read<T>(IVirtualMemoryManager memory, long position) where T : struct
|
||||||
{
|
{
|
||||||
long size = Marshal.SizeOf<T>();
|
long size = Marshal.SizeOf<T>();
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ namespace Ryujinx.Cpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static void Write<T>(MemoryManager memory, long position, T value) where T : struct
|
public unsafe static void Write<T>(IVirtualMemoryManager memory, long position, T value) where T : struct
|
||||||
{
|
{
|
||||||
long size = Marshal.SizeOf<T>();
|
long size = Marshal.SizeOf<T>();
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ namespace Ryujinx.Cpu
|
||||||
memory.Write((ulong)position, data);
|
memory.Write((ulong)position, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReadAsciiString(MemoryManager memory, long position, long maxSize = -1)
|
public static string ReadAsciiString(IVirtualMemoryManager memory, long position, long maxSize = -1)
|
||||||
{
|
{
|
||||||
using (MemoryStream ms = new MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Cpu
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a CPU memory manager.
|
/// Represents a CPU memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MemoryManager : IMemoryManager, IDisposable, IVirtualMemoryManager
|
public sealed class MemoryManager : IMemoryManager, IVirtualMemoryManager, IDisposable
|
||||||
{
|
{
|
||||||
public const int PageBits = 12;
|
public const int PageBits = 12;
|
||||||
public const int PageSize = 1 << PageBits;
|
public const int PageSize = 1 << PageBits;
|
||||||
|
@ -468,6 +468,11 @@ namespace Ryujinx.Cpu
|
||||||
/// <returns>True if the entire range is mapped, false otherwise</returns>
|
/// <returns>True if the entire range is mapped, false otherwise</returns>
|
||||||
public bool IsRangeMapped(ulong va, ulong size)
|
public bool IsRangeMapped(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
|
if (size == 0UL)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
||||||
|
|
||||||
va &= ~(ulong)PageMask;
|
va &= ~(ulong)PageMask;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Cpu.Tracking;
|
using Ryujinx.Cpu.Tracking;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -12,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class PhysicalMemory
|
class PhysicalMemory
|
||||||
{
|
{
|
||||||
public const int PageSize = Cpu.MemoryManager.PageSize;
|
public const int PageSize = 0x1000;
|
||||||
|
|
||||||
private readonly Cpu.MemoryManager _cpuMemory;
|
private readonly Cpu.MemoryManager _cpuMemory;
|
||||||
|
|
||||||
|
|
|
@ -14,23 +14,26 @@ namespace Ryujinx.HLE.Exceptions
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServiceNotImplementedException : Exception
|
internal class ServiceNotImplementedException : Exception
|
||||||
{
|
{
|
||||||
|
public IIpcService Service { get; }
|
||||||
public ServiceCtx Context { get; }
|
public ServiceCtx Context { get; }
|
||||||
public IpcMessage Request { get; }
|
public IpcMessage Request { get; }
|
||||||
|
|
||||||
public ServiceNotImplementedException(ServiceCtx context)
|
public ServiceNotImplementedException(IIpcService service, ServiceCtx context)
|
||||||
: this(context, "The service call is not implemented.")
|
: this(service, context, "The service call is not implemented.")
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public ServiceNotImplementedException(ServiceCtx context, string message)
|
public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message)
|
||||||
: base(message)
|
: base(message)
|
||||||
{
|
{
|
||||||
|
Service = service;
|
||||||
Context = context;
|
Context = context;
|
||||||
Request = context.Request;
|
Request = context.Request;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServiceNotImplementedException(ServiceCtx context, string message, Exception inner)
|
public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message, Exception inner)
|
||||||
: base(message, inner)
|
: base(message, inner)
|
||||||
{
|
{
|
||||||
|
Service = service;
|
||||||
Context = context;
|
Context = context;
|
||||||
Request = context.Request;
|
Request = context.Request;
|
||||||
}
|
}
|
||||||
|
@ -59,17 +62,16 @@ namespace Ryujinx.HLE.Exceptions
|
||||||
|
|
||||||
if (callingType != null && callingMethod != null)
|
if (callingType != null && callingMethod != null)
|
||||||
{
|
{
|
||||||
var ipcService = Context.Session.Service;
|
var ipcCommands = Service.Commands;
|
||||||
var ipcCommands = ipcService.Commands;
|
|
||||||
|
|
||||||
// Find the handler for the method called
|
// Find the handler for the method called
|
||||||
var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value as MethodBase == callingMethod);
|
var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value == callingMethod);
|
||||||
var ipcCommandId = ipcHandler.Key;
|
var ipcCommandId = ipcHandler.Key;
|
||||||
var ipcMethod = ipcHandler.Value;
|
var ipcMethod = ipcHandler.Value;
|
||||||
|
|
||||||
if (ipcMethod != null)
|
if (ipcMethod != null)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"Service Command: {ipcService.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})");
|
sb.AppendLine($"Service Command: {Service.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
24
Ryujinx.HLE/HOS/ArmProcessContext.cs
Normal file
24
Ryujinx.HLE/HOS/ArmProcessContext.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS
|
||||||
|
{
|
||||||
|
class ArmProcessContext : IProcessContext
|
||||||
|
{
|
||||||
|
private readonly MemoryManager _memoryManager;
|
||||||
|
private readonly CpuContext _cpuContext;
|
||||||
|
|
||||||
|
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
||||||
|
|
||||||
|
public ArmProcessContext(MemoryManager memoryManager)
|
||||||
|
{
|
||||||
|
_memoryManager = memoryManager;
|
||||||
|
_cpuContext = new CpuContext(memoryManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(ExecutionContext context, ulong codeAddress) => _cpuContext.Execute(context, codeAddress);
|
||||||
|
public void Dispose() => _memoryManager.Dispose();
|
||||||
|
}
|
||||||
|
}
|
14
Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
Normal file
14
Ryujinx.HLE/HOS/ArmProcessContextFactory.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS
|
||||||
|
{
|
||||||
|
class ArmProcessContextFactory : IProcessContextFactory
|
||||||
|
{
|
||||||
|
public IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler)
|
||||||
|
{
|
||||||
|
return new ArmProcessContext(new MemoryManager(backingMemory, addressSpaceSize, invalidAccessHandler));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -120,11 +120,11 @@ namespace Ryujinx.HLE.HOS
|
||||||
iirsPageList.AddRange(iirsPa, IirsSize / KMemoryManager.PageSize);
|
iirsPageList.AddRange(iirsPa, IirsSize / KMemoryManager.PageSize);
|
||||||
timePageList.AddRange(timePa, TimeSize / KMemoryManager.PageSize);
|
timePageList.AddRange(timePa, TimeSize / KMemoryManager.PageSize);
|
||||||
|
|
||||||
HidSharedMem = new KSharedMemory(KernelContext, hidPageList, 0, 0, MemoryPermission.Read);
|
HidSharedMem = new KSharedMemory(KernelContext, hidPageList, 0, 0, KMemoryPermission.Read);
|
||||||
FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, MemoryPermission.Read);
|
FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, KMemoryPermission.Read);
|
||||||
IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, MemoryPermission.Read);
|
IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, KMemoryPermission.Read);
|
||||||
|
|
||||||
KSharedMemory timeSharedMemory = new KSharedMemory(KernelContext, timePageList, 0, 0, MemoryPermission.Read);
|
KSharedMemory timeSharedMemory = new KSharedMemory(KernelContext, timePageList, 0, 0, KMemoryPermission.Read);
|
||||||
|
|
||||||
TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timePa - DramMemoryMap.DramBase, TimeSize);
|
TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timePa - DramMemoryMap.DramBase, TimeSize);
|
||||||
|
|
||||||
|
@ -134,8 +134,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
Font = new SharedFontManager(device, fontPa - DramMemoryMap.DramBase);
|
Font = new SharedFontManager(device, fontPa - DramMemoryMap.DramBase);
|
||||||
|
|
||||||
IUserInterface.InitializePort(this);
|
|
||||||
|
|
||||||
VsyncEvent = new KEvent(KernelContext);
|
VsyncEvent = new KEvent(KernelContext);
|
||||||
|
|
||||||
DisplayResolutionChangeEvent = new KEvent(KernelContext);
|
DisplayResolutionChangeEvent = new KEvent(KernelContext);
|
||||||
|
@ -224,6 +222,16 @@ namespace Ryujinx.HLE.HOS
|
||||||
AudioRendererManager.Initialize(writableEvents, devices);
|
AudioRendererManager.Initialize(writableEvents, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InitializeServices()
|
||||||
|
{
|
||||||
|
IUserInterface sm = new IUserInterface(KernelContext);
|
||||||
|
|
||||||
|
// Wait until SM server thread is done with initialization,
|
||||||
|
// only then doing connections to SM is safe.
|
||||||
|
sm.Server.InitDone.WaitOne();
|
||||||
|
sm.Server.InitDone.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public void LoadKip(string kipPath)
|
public void LoadKip(string kipPath)
|
||||||
{
|
{
|
||||||
using IStorage kipFile = new LocalStorage(kipPath, FileAccess.Read);
|
using IStorage kipFile = new LocalStorage(kipPath, FileAccess.Read);
|
||||||
|
|
|
@ -84,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
|
|
||||||
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
||||||
|
|
||||||
|
if (rawDataSize != 0)
|
||||||
|
{
|
||||||
|
rawDataSize -= (int)pad0;
|
||||||
|
}
|
||||||
|
|
||||||
reader.BaseStream.Seek(pad0, SeekOrigin.Current);
|
reader.BaseStream.Seek(pad0, SeekOrigin.Current);
|
||||||
|
|
||||||
int recvListCount = recvListFlags - 2;
|
int recvListCount = recvListFlags - 2;
|
||||||
|
@ -107,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetBytes(long cmdPtr)
|
public byte[] GetBytes(long cmdPtr, ulong recvListAddr)
|
||||||
{
|
{
|
||||||
using (MemoryStream ms = new MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
|
@ -131,7 +136,11 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
|
|
||||||
int dataLength = RawData?.Length ?? 0;
|
int dataLength = RawData?.Length ?? 0;
|
||||||
|
|
||||||
int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length);
|
dataLength = (dataLength + 3) & ~3;
|
||||||
|
|
||||||
|
int rawLength = dataLength;
|
||||||
|
|
||||||
|
int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length + PtrBuff.Count * 8);
|
||||||
|
|
||||||
// Apparently, padding after Raw Data is 16 bytes, however when there is
|
// Apparently, padding after Raw Data is 16 bytes, however when there is
|
||||||
// padding before Raw Data too, we need to subtract the size of this padding.
|
// padding before Raw Data too, we need to subtract the size of this padding.
|
||||||
|
@ -140,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
|
|
||||||
dataLength = (dataLength + pad0 + pad1) / 4;
|
dataLength = (dataLength + pad0 + pad1) / 4;
|
||||||
|
|
||||||
word1 = dataLength & 0x3ff;
|
word1 = (dataLength & 0x3ff) | (2 << 10);
|
||||||
|
|
||||||
if (HandleDesc != null)
|
if (HandleDesc != null)
|
||||||
{
|
{
|
||||||
|
@ -151,14 +160,22 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
writer.Write(word1);
|
writer.Write(word1);
|
||||||
writer.Write(handleData);
|
writer.Write(handleData);
|
||||||
|
|
||||||
|
for (int index = 0; index < PtrBuff.Count; index++)
|
||||||
|
{
|
||||||
|
writer.Write(PtrBuff[index].GetWord0());
|
||||||
|
writer.Write(PtrBuff[index].GetWord1());
|
||||||
|
}
|
||||||
|
|
||||||
ms.Seek(pad0, SeekOrigin.Current);
|
ms.Seek(pad0, SeekOrigin.Current);
|
||||||
|
|
||||||
if (RawData != null)
|
if (RawData != null)
|
||||||
{
|
{
|
||||||
writer.Write(RawData);
|
writer.Write(RawData);
|
||||||
|
ms.Seek(rawLength - RawData.Length, SeekOrigin.Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Write(new byte[pad1]);
|
writer.Write(new byte[pad1]);
|
||||||
|
writer.Write(recvListAddr);
|
||||||
|
|
||||||
return ms.ToArray();
|
return ms.ToArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,13 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
public int Index { get; private set; }
|
public int Index { get; private set; }
|
||||||
public long Size { get; private set; }
|
public long Size { get; private set; }
|
||||||
|
|
||||||
|
public IpcPtrBuffDesc(long position, int index, long size)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Index = index;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
|
||||||
public IpcPtrBuffDesc(BinaryReader reader)
|
public IpcPtrBuffDesc(BinaryReader reader)
|
||||||
{
|
{
|
||||||
long word0 = reader.ReadUInt32();
|
long word0 = reader.ReadUInt32();
|
||||||
|
@ -22,5 +29,25 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
|
|
||||||
Size = (ushort)(word0 >> 16);
|
Size = (ushort)(word0 >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint GetWord0()
|
||||||
|
{
|
||||||
|
uint word0;
|
||||||
|
|
||||||
|
word0 = (uint)((Position & 0x0f00000000) >> 20);
|
||||||
|
word0 |= (uint)((Position & 0x7000000000) >> 30);
|
||||||
|
|
||||||
|
word0 |= (uint)(Index & 0x03f) << 0;
|
||||||
|
word0 |= (uint)(Index & 0x1c0) << 3;
|
||||||
|
|
||||||
|
word0 |= (uint)Size << 16;
|
||||||
|
|
||||||
|
return word0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetWord1()
|
||||||
|
{
|
||||||
|
return (uint)Position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,12 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
public long Position { get; private set; }
|
public long Position { get; private set; }
|
||||||
public long Size { get; private set; }
|
public long Size { get; private set; }
|
||||||
|
|
||||||
|
public IpcRecvListBuffDesc(long position, long size)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
|
||||||
public IpcRecvListBuffDesc(BinaryReader reader)
|
public IpcRecvListBuffDesc(BinaryReader reader)
|
||||||
{
|
{
|
||||||
long value = reader.ReadInt64();
|
long value = reader.ReadInt64();
|
||||||
|
|
11
Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
Normal file
11
Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||||
|
{
|
||||||
|
struct OnScopeExit : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Action _action;
|
||||||
|
public OnScopeExit(Action action) => _action = action;
|
||||||
|
public void Dispose() => _action();
|
||||||
|
}
|
||||||
|
}
|
|
@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
copySize,
|
copySize,
|
||||||
stateMask,
|
stateMask,
|
||||||
stateMask,
|
stateMask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
attributeMask,
|
attributeMask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
desc.ServerAddress);
|
desc.ServerAddress);
|
||||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
clientEndAddr - clientEndAddrTruncated,
|
clientEndAddr - clientEndAddrTruncated,
|
||||||
stateMask,
|
stateMask,
|
||||||
stateMask,
|
stateMask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
attributeMask,
|
attributeMask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
serverEndAddrTruncated);
|
serverEndAddrTruncated);
|
||||||
|
|
|
@ -14,10 +14,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
|
|
||||||
public bool IsLight => _parent.IsLight;
|
public bool IsLight => _parent.IsLight;
|
||||||
|
|
||||||
// TODO: Remove that, we need it for now to allow HLE
|
|
||||||
// SM implementation to work with the new IPC system.
|
|
||||||
public IpcService Service { get; set; }
|
|
||||||
|
|
||||||
public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
|
public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
|
||||||
{
|
{
|
||||||
_maxSessions = maxSessions;
|
_maxSessions = maxSessions;
|
||||||
|
@ -45,11 +41,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
|
|
||||||
KSession session = new KSession(KernelContext, this);
|
KSession session = new KSession(KernelContext, this);
|
||||||
|
|
||||||
if (Service != null)
|
|
||||||
{
|
|
||||||
session.ClientSession.Service = Service;
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
|
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
|
|
|
@ -16,10 +16,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
|
|
||||||
public KClientPort ParentPort { get; }
|
public KClientPort ParentPort { get; }
|
||||||
|
|
||||||
// TODO: Remove that, we need it for now to allow HLE
|
|
||||||
// services implementation to work with the new IPC system.
|
|
||||||
public IpcService Service { get; set; }
|
|
||||||
|
|
||||||
public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context)
|
public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
|
@ -84,11 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
{
|
{
|
||||||
_parent.DisconnectClient();
|
_parent.DisconnectClient();
|
||||||
_parent.DecrementReferenceCount();
|
_parent.DecrementReferenceCount();
|
||||||
|
|
||||||
if (Service is IDisposable disposableObj)
|
|
||||||
{
|
|
||||||
disposableObj.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -430,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
descriptor.BufferAddress,
|
descriptor.BufferAddress,
|
||||||
MemoryState.IsPoolAllocated,
|
MemoryState.IsPoolAllocated,
|
||||||
MemoryState.IsPoolAllocated,
|
MemoryState.IsPoolAllocated,
|
||||||
MemoryPermission.Read,
|
KMemoryPermission.Read,
|
||||||
MemoryAttribute.Uncached,
|
MemoryAttribute.Uncached,
|
||||||
MemoryAttribute.None);
|
MemoryAttribute.None);
|
||||||
|
|
||||||
|
@ -473,9 +473,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
bool notReceiveDesc = isSendDesc || isExchangeDesc;
|
bool notReceiveDesc = isSendDesc || isExchangeDesc;
|
||||||
bool isReceiveDesc = !notReceiveDesc;
|
bool isReceiveDesc = !notReceiveDesc;
|
||||||
|
|
||||||
MemoryPermission permission = index >= clientHeader.SendBuffersCount
|
KMemoryPermission permission = index >= clientHeader.SendBuffersCount
|
||||||
? MemoryPermission.ReadAndWrite
|
? KMemoryPermission.ReadAndWrite
|
||||||
: MemoryPermission.Read;
|
: KMemoryPermission.Read;
|
||||||
|
|
||||||
uint sizeHigh4 = (descWord2 >> 24) & 0xf;
|
uint sizeHigh4 = (descWord2 >> 24) & 0xf;
|
||||||
|
|
||||||
|
@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
|
|
||||||
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
||||||
{
|
{
|
||||||
MemoryPermission permission = clientMsg.IsCustom
|
KMemoryPermission permission = clientMsg.IsCustom
|
||||||
? MemoryPermission.None
|
? KMemoryPermission.None
|
||||||
: MemoryPermission.Read;
|
: KMemoryPermission.Read;
|
||||||
|
|
||||||
clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
|
clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
|
||||||
copyDst,
|
copyDst,
|
||||||
|
@ -795,7 +795,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
descriptor.BufferSize,
|
descriptor.BufferSize,
|
||||||
MemoryState.IsPoolAllocated,
|
MemoryState.IsPoolAllocated,
|
||||||
MemoryState.IsPoolAllocated,
|
MemoryState.IsPoolAllocated,
|
||||||
MemoryPermission.Read,
|
KMemoryPermission.Read,
|
||||||
MemoryAttribute.Uncached,
|
MemoryAttribute.Uncached,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
descriptor.BufferAddress);
|
descriptor.BufferAddress);
|
||||||
|
@ -849,9 +849,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
|
|
||||||
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
||||||
{
|
{
|
||||||
MemoryPermission permission = clientMsg.IsCustom
|
KMemoryPermission permission = clientMsg.IsCustom
|
||||||
? MemoryPermission.None
|
? KMemoryPermission.None
|
||||||
: MemoryPermission.Read;
|
: KMemoryPermission.Read;
|
||||||
|
|
||||||
clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
|
clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
|
||||||
copyDst,
|
copyDst,
|
||||||
|
@ -898,11 +898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
return new MessageHeader(word0, word1, word2);
|
return new MessageHeader(word0, word1, word2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KernelResult GetCopyObjectHandle(
|
private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
|
||||||
KThread srcThread,
|
|
||||||
KProcess dstProcess,
|
|
||||||
int srcHandle,
|
|
||||||
out int dstHandle)
|
|
||||||
{
|
{
|
||||||
dstHandle = 0;
|
dstHandle = 0;
|
||||||
|
|
||||||
|
@ -933,11 +929,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private KernelResult GetMoveObjectHandle(
|
private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
|
||||||
KProcess srcProcess,
|
|
||||||
KProcess dstProcess,
|
|
||||||
int srcHandle,
|
|
||||||
out int dstHandle)
|
|
||||||
{
|
{
|
||||||
dstHandle = 0;
|
dstHandle = 0;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
{
|
{
|
||||||
class KSession : KAutoObject, IDisposable
|
class KSession : KAutoObject
|
||||||
{
|
{
|
||||||
public KServerSession ServerSession { get; }
|
public KServerSession ServerSession { get; }
|
||||||
public KClientSession ClientSession { get; }
|
public KClientSession ClientSession { get; }
|
||||||
|
@ -37,19 +37,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && ClientSession.Service is IDisposable disposableService)
|
|
||||||
{
|
|
||||||
disposableService.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Destroy()
|
protected override void Destroy()
|
||||||
{
|
{
|
||||||
if (_hasBeenInitialized)
|
if (_hasBeenInitialized)
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
Device = device;
|
Device = device;
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
|
|
||||||
Syscall = new Syscall(device, this);
|
Syscall = new Syscall(this);
|
||||||
|
|
||||||
SyscallHandler = new SyscallHandler(this);
|
SyscallHandler = new SyscallHandler(this);
|
||||||
|
|
||||||
|
|
38
Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
Normal file
38
Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
{
|
||||||
|
static class KernelStatic
|
||||||
|
{
|
||||||
|
[ThreadStatic]
|
||||||
|
private static KernelContext Context;
|
||||||
|
|
||||||
|
public static void YieldUntilCompletion(Action action)
|
||||||
|
{
|
||||||
|
YieldUntilCompletion(Task.Factory.StartNew(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void YieldUntilCompletion(Task task)
|
||||||
|
{
|
||||||
|
KThread currentThread = Context.Scheduler.GetCurrentThread();
|
||||||
|
|
||||||
|
Context.CriticalSection.Enter();
|
||||||
|
|
||||||
|
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||||
|
|
||||||
|
task.ContinueWith((antecedent) =>
|
||||||
|
{
|
||||||
|
currentThread.Reschedule(ThreadSchedState.Running);
|
||||||
|
});
|
||||||
|
|
||||||
|
Context.CriticalSection.Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SetKernelContext(KernelContext context)
|
||||||
|
{
|
||||||
|
Context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
public ulong PagesCount { get; private set; }
|
public ulong PagesCount { get; private set; }
|
||||||
|
|
||||||
public MemoryState State { get; private set; }
|
public MemoryState State { get; private set; }
|
||||||
public MemoryPermission Permission { get; private set; }
|
public KMemoryPermission Permission { get; private set; }
|
||||||
public MemoryAttribute Attribute { get; private set; }
|
public MemoryAttribute Attribute { get; private set; }
|
||||||
public MemoryPermission SourcePermission { get; private set; }
|
public KMemoryPermission SourcePermission { get; private set; }
|
||||||
|
|
||||||
public int IpcRefCount { get; private set; }
|
public int IpcRefCount { get; private set; }
|
||||||
public int DeviceRefCount { get; private set; }
|
public int DeviceRefCount { get; private set; }
|
||||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong baseAddress,
|
ulong baseAddress,
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryAttribute attribute,
|
MemoryAttribute attribute,
|
||||||
int ipcRefCount = 0,
|
int ipcRefCount = 0,
|
||||||
int deviceRefCount = 0)
|
int deviceRefCount = 0)
|
||||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
DeviceRefCount = deviceRefCount;
|
DeviceRefCount = deviceRefCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetState(MemoryPermission permission, MemoryState state, MemoryAttribute attribute)
|
public void SetState(KMemoryPermission permission, MemoryState state, MemoryAttribute attribute)
|
||||||
{
|
{
|
||||||
Permission = permission;
|
Permission = permission;
|
||||||
State = state;
|
State = state;
|
||||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
Attribute |= attribute;
|
Attribute |= attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetIpcMappingPermission(MemoryPermission newPermission)
|
public void SetIpcMappingPermission(KMemoryPermission newPermission)
|
||||||
{
|
{
|
||||||
int oldIpcRefCount = IpcRefCount++;
|
int oldIpcRefCount = IpcRefCount++;
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
SourcePermission = Permission;
|
SourcePermission = Permission;
|
||||||
|
|
||||||
Permission &= ~MemoryPermission.ReadAndWrite;
|
Permission &= ~KMemoryPermission.ReadAndWrite;
|
||||||
Permission |= MemoryPermission.ReadAndWrite & newPermission;
|
Permission |= KMemoryPermission.ReadAndWrite & newPermission;
|
||||||
}
|
}
|
||||||
|
|
||||||
Attribute |= MemoryAttribute.IpcMapped;
|
Attribute |= MemoryAttribute.IpcMapped;
|
||||||
|
@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
Permission = SourcePermission;
|
Permission = SourcePermission;
|
||||||
|
|
||||||
SourcePermission = MemoryPermission.None;
|
SourcePermission = KMemoryPermission.None;
|
||||||
|
|
||||||
Attribute &= ~MemoryAttribute.IpcMapped;
|
Attribute &= ~MemoryAttribute.IpcMapped;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
public ulong Size { get; }
|
public ulong Size { get; }
|
||||||
|
|
||||||
public MemoryState State { get; }
|
public MemoryState State { get; }
|
||||||
public MemoryPermission Permission { get; }
|
public KMemoryPermission Permission { get; }
|
||||||
public MemoryAttribute Attribute { get; }
|
public MemoryAttribute Attribute { get; }
|
||||||
public MemoryPermission SourcePermission { get; }
|
public KMemoryPermission SourcePermission { get; }
|
||||||
|
|
||||||
public int IpcRefCount { get; }
|
public int IpcRefCount { get; }
|
||||||
public int DeviceRefCount { get; }
|
public int DeviceRefCount { get; }
|
||||||
|
@ -17,9 +17,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryAttribute attribute,
|
MemoryAttribute attribute,
|
||||||
MemoryPermission sourcePermission,
|
KMemoryPermission sourcePermission,
|
||||||
int ipcRefCount,
|
int ipcRefCount,
|
||||||
int deviceRefCount)
|
int deviceRefCount)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Cpu;
|
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
|
@ -27,11 +28,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
// needs to be split in 2, plus one block that will be the new one inserted.
|
// needs to be split in 2, plus one block that will be the new one inserted.
|
||||||
private const int MaxBlocksNeededForInsertion = 2;
|
private const int MaxBlocksNeededForInsertion = 2;
|
||||||
|
|
||||||
private LinkedList<KMemoryBlock> _blocks;
|
private readonly LinkedList<KMemoryBlock> _blocks;
|
||||||
|
|
||||||
private MemoryManager _cpuMemory;
|
private readonly IVirtualMemoryManager _cpuMemory;
|
||||||
|
|
||||||
private KernelContext _context;
|
private readonly KernelContext _context;
|
||||||
|
|
||||||
public ulong AddrSpaceStart { get; private set; }
|
public ulong AddrSpaceStart { get; private set; }
|
||||||
public ulong AddrSpaceEnd { get; private set; }
|
public ulong AddrSpaceEnd { get; private set; }
|
||||||
|
@ -73,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
private MersenneTwister _randomNumberGenerator;
|
private MersenneTwister _randomNumberGenerator;
|
||||||
|
|
||||||
public KMemoryManager(KernelContext context, MemoryManager cpuMemory)
|
public KMemoryManager(KernelContext context, IVirtualMemoryManager cpuMemory)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_cpuMemory = cpuMemory;
|
_cpuMemory = cpuMemory;
|
||||||
|
@ -352,7 +353,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
addrSpaceStart,
|
addrSpaceStart,
|
||||||
addrSpacePagesCount,
|
addrSpacePagesCount,
|
||||||
MemoryState.Unmapped,
|
MemoryState.Unmapped,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.None));
|
MemoryAttribute.None));
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
|
@ -362,13 +363,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong address,
|
ulong address,
|
||||||
KPageList pageList,
|
KPageList pageList,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
MemoryPermission permission)
|
KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong pagesCount = pageList.GetPagesCount();
|
ulong pagesCount = pageList.GetPagesCount();
|
||||||
|
|
||||||
ulong size = pagesCount * PageSize;
|
ulong size = pagesCount * PageSize;
|
||||||
|
|
||||||
if (!ValidateRegionForState(address, size, state))
|
if (!CanContain(address, size, state))
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidMemState;
|
return KernelResult.InvalidMemState;
|
||||||
}
|
}
|
||||||
|
@ -437,8 +438,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
stateExpected,
|
stateExpected,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -467,13 +468,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission)
|
public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO.
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult MapIoMemory(long address, long size, MemoryPermission permission)
|
public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO.
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
|
@ -487,7 +488,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong regionStart,
|
ulong regionStart,
|
||||||
ulong regionPagesCount,
|
ulong regionPagesCount,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
out ulong address)
|
out ulong address)
|
||||||
{
|
{
|
||||||
address = 0;
|
address = 0;
|
||||||
|
@ -496,7 +497,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
ulong regionEndAddr = regionStart + regionSize;
|
ulong regionEndAddr = regionStart + regionSize;
|
||||||
|
|
||||||
if (!ValidateRegionForState(regionStart, regionSize, state))
|
if (!CanContain(regionStart, regionSize, state))
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidMemState;
|
return KernelResult.InvalidMemState;
|
||||||
}
|
}
|
||||||
|
@ -547,11 +548,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
MemoryPermission permission)
|
KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong size = pagesCount * PageSize;
|
ulong size = pagesCount * PageSize;
|
||||||
|
|
||||||
if (!ValidateRegionForState(address, size, state))
|
if (!CanContain(address, size, state))
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidMemState;
|
return KernelResult.InvalidMemState;
|
||||||
}
|
}
|
||||||
|
@ -596,13 +597,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
MemoryState.Heap,
|
MemoryState.Heap,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
out MemoryState state,
|
out MemoryState state,
|
||||||
out MemoryPermission permission,
|
out KMemoryPermission permission,
|
||||||
out _);
|
out _);
|
||||||
|
|
||||||
success &= IsUnmapped(dst, size);
|
success &= IsUnmapped(dst, size);
|
||||||
|
@ -618,14 +619,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
AddVaRangeToPageList(pageList, src, pagesCount);
|
AddVaRangeToPageList(pageList, src, pagesCount);
|
||||||
|
|
||||||
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
|
KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = MapPages(dst, pageList, MemoryPermission.None);
|
result = MapPages(dst, pageList, KMemoryPermission.None);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -634,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed);
|
InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
|
||||||
InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
|
InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
|
@ -657,8 +658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
MemoryState.Heap,
|
MemoryState.Heap,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.Borrowed,
|
MemoryAttribute.Borrowed,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -671,8 +672,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
PageSize,
|
PageSize,
|
||||||
MemoryState.UnmapProcessCodeMemoryAllowed,
|
MemoryState.UnmapProcessCodeMemoryAllowed,
|
||||||
MemoryState.UnmapProcessCodeMemoryAllowed,
|
MemoryState.UnmapProcessCodeMemoryAllowed,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -685,8 +686,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
state,
|
state,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None);
|
MemoryAttribute.None);
|
||||||
|
|
||||||
|
@ -707,7 +708,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
|
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
|
||||||
InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
|
InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
@ -788,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
_currentHeapAddr,
|
_currentHeapAddr,
|
||||||
pagesCount,
|
pagesCount,
|
||||||
pageList,
|
pageList,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryOperation.MapVa);
|
MemoryOperation.MapVa);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
|
@ -798,7 +799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
|
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -816,8 +817,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
sizeDelta,
|
sizeDelta,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
MemoryState.Heap,
|
MemoryState.Heap,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -886,13 +887,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.AttributeChangeAllowed,
|
MemoryState.AttributeChangeAllowed,
|
||||||
MemoryState.AttributeChangeAllowed,
|
MemoryState.AttributeChangeAllowed,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.BorrowedAndIpcMapped,
|
MemoryAttribute.BorrowedAndIpcMapped,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.DeviceMappedAndUncached,
|
MemoryAttribute.DeviceMappedAndUncached,
|
||||||
out MemoryState state,
|
out MemoryState state,
|
||||||
out MemoryPermission permission,
|
out KMemoryPermission permission,
|
||||||
out MemoryAttribute attribute))
|
out MemoryAttribute attribute))
|
||||||
{
|
{
|
||||||
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
|
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
|
||||||
|
@ -932,9 +933,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
AddrSpaceEnd,
|
AddrSpaceEnd,
|
||||||
~AddrSpaceEnd + 1,
|
~AddrSpaceEnd + 1,
|
||||||
MemoryState.Reserved,
|
MemoryState.Reserved,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
@ -951,8 +952,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.MapAllowed,
|
MemoryState.MapAllowed,
|
||||||
MemoryState.MapAllowed,
|
MemoryState.MapAllowed,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -975,18 +976,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
AddVaRangeToPageList(pageList, src, pagesCount);
|
AddVaRangeToPageList(pageList, src, pagesCount);
|
||||||
|
|
||||||
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
|
KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite);
|
result = MapPages(dst, pageList, KMemoryPermission.ReadAndWrite);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
if (MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite) != KernelResult.Success)
|
if (MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite) != KernelResult.Success)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Unexpected failure reverting memory permission.");
|
throw new InvalidOperationException("Unexpected failure reverting memory permission.");
|
||||||
}
|
}
|
||||||
|
@ -994,8 +995,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed);
|
InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
|
||||||
InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite);
|
InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
@ -1017,8 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
stateExpected,
|
stateExpected,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -1058,8 +1059,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.MapAllowed,
|
MemoryState.MapAllowed,
|
||||||
MemoryState.MapAllowed,
|
MemoryState.MapAllowed,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.Borrowed,
|
MemoryAttribute.Borrowed,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -1072,13 +1073,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
MemoryState.Stack,
|
MemoryState.Stack,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
out _,
|
out _,
|
||||||
out MemoryPermission dstPermission,
|
out KMemoryPermission dstPermission,
|
||||||
out _);
|
out _);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
|
@ -1108,7 +1109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite);
|
result = MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -1117,7 +1118,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite);
|
InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
|
||||||
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
|
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
|
@ -1129,7 +1130,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission)
|
public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
lock (_blocks)
|
lock (_blocks)
|
||||||
{
|
{
|
||||||
|
@ -1138,20 +1139,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.ProcessPermissionChangeAllowed,
|
MemoryState.ProcessPermissionChangeAllowed,
|
||||||
MemoryState.ProcessPermissionChangeAllowed,
|
MemoryState.ProcessPermissionChangeAllowed,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
out MemoryState oldState,
|
out MemoryState oldState,
|
||||||
out MemoryPermission oldPermission,
|
out KMemoryPermission oldPermission,
|
||||||
out _))
|
out _))
|
||||||
{
|
{
|
||||||
MemoryState newState = oldState;
|
MemoryState newState = oldState;
|
||||||
|
|
||||||
// If writing into the code region is allowed, then we need
|
// If writing into the code region is allowed, then we need
|
||||||
// to change it to mutable.
|
// to change it to mutable.
|
||||||
if ((permission & MemoryPermission.Write) != 0)
|
if ((permission & KMemoryPermission.Write) != 0)
|
||||||
{
|
{
|
||||||
if (oldState == MemoryState.CodeStatic)
|
if (oldState == MemoryState.CodeStatic)
|
||||||
{
|
{
|
||||||
|
@ -1176,7 +1177,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
ulong pagesCount = size / PageSize;
|
ulong pagesCount = size / PageSize;
|
||||||
|
|
||||||
MemoryOperation operation = (permission & MemoryPermission.Execute) != 0
|
MemoryOperation operation = (permission & KMemoryPermission.Execute) != 0
|
||||||
? MemoryOperation.ChangePermsAndAttributes
|
? MemoryOperation.ChangePermsAndAttributes
|
||||||
: MemoryOperation.ChangePermRw;
|
: MemoryOperation.ChangePermRw;
|
||||||
|
|
||||||
|
@ -1270,10 +1271,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
address,
|
address,
|
||||||
pagesCount,
|
pagesCount,
|
||||||
MemoryState.Unmapped,
|
MemoryState.Unmapped,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryState.Heap,
|
MemoryState.Heap,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.None);
|
MemoryAttribute.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1410,7 +1411,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
pagesCount,
|
pagesCount,
|
||||||
srcPa,
|
srcPa,
|
||||||
true,
|
true,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryOperation.MapPa);
|
MemoryOperation.MapPa);
|
||||||
|
|
||||||
dstVa += pagesCount * PageSize;
|
dstVa += pagesCount * PageSize;
|
||||||
|
@ -1428,7 +1429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong src,
|
ulong src,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected)
|
MemoryAttribute attributeExpected)
|
||||||
{
|
{
|
||||||
|
@ -1450,7 +1451,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected,
|
MemoryAttribute attributeExpected,
|
||||||
ulong src)
|
ulong src)
|
||||||
|
@ -1474,7 +1475,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong serverAddress,
|
ulong serverAddress,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected,
|
MemoryAttribute attributeExpected,
|
||||||
bool toServer)
|
bool toServer)
|
||||||
|
@ -1529,7 +1530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong size,
|
ulong size,
|
||||||
ulong src,
|
ulong src,
|
||||||
KMemoryManager sourceMemMgr,
|
KMemoryManager sourceMemMgr,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
bool copyData,
|
bool copyData,
|
||||||
out ulong dst)
|
out ulong dst)
|
||||||
|
@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
private KernelResult GetPagesForMappingIntoAnotherProcess(
|
private KernelResult GetPagesForMappingIntoAnotherProcess(
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
bool copyData,
|
bool copyData,
|
||||||
bool aslrDisabled,
|
bool aslrDisabled,
|
||||||
|
@ -1600,9 +1601,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
default: return KernelResult.InvalidCombination;
|
default: return KernelResult.InvalidCombination;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPermission permissionMask = permission == MemoryPermission.ReadAndWrite
|
KMemoryPermission permissionMask = permission == KMemoryPermission.ReadAndWrite
|
||||||
? MemoryPermission.None
|
? KMemoryPermission.None
|
||||||
: MemoryPermission.Read;
|
: KMemoryPermission.Read;
|
||||||
|
|
||||||
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
|
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
|
||||||
|
|
||||||
|
@ -1634,7 +1635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited))
|
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited))
|
||||||
{
|
{
|
||||||
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
|
if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
|
||||||
{
|
{
|
||||||
ulong blockAddress = GetAddrInRange(info, addressRounded);
|
ulong blockAddress = GetAddrInRange(info, addressRounded);
|
||||||
ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited);
|
ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited);
|
||||||
|
@ -1661,7 +1662,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
if (addressRounded < endAddrTruncated)
|
if (addressRounded < endAddrTruncated)
|
||||||
{
|
{
|
||||||
foreach (KMemoryInfo info in IterateOverRange(addressTruncated, endAddrRounded))
|
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrTruncated))
|
||||||
{
|
{
|
||||||
// Check if the block state matches what we expect.
|
// Check if the block state matches what we expect.
|
||||||
if ((info.State & stateMask) != stateMask ||
|
if ((info.State & stateMask) != stateMask ||
|
||||||
|
@ -1678,7 +1679,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
ulong blockPagesCount = blockSize / PageSize;
|
ulong blockPagesCount = blockSize / PageSize;
|
||||||
|
|
||||||
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
|
if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
|
||||||
{
|
{
|
||||||
result = DoMmuOperation(
|
result = DoMmuOperation(
|
||||||
blockAddress,
|
blockAddress,
|
||||||
|
@ -1784,7 +1785,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
ulong unusedSizeBefore = address - addressTruncated;
|
ulong unusedSizeBefore = address - addressTruncated;
|
||||||
|
|
||||||
_context.Memory.ZeroFill(dstFirstPagePa, unusedSizeBefore);
|
_context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore);
|
||||||
|
|
||||||
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
|
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
|
||||||
|
|
||||||
|
@ -1803,7 +1804,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
if (unusedSizeAfter != 0)
|
if (unusedSizeAfter != 0)
|
||||||
{
|
{
|
||||||
_context.Memory.ZeroFill(firstPageFillAddress, unusedSizeAfter);
|
_context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success)
|
if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success)
|
||||||
|
@ -1865,7 +1866,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
unusedSizeAfter = PageSize;
|
unusedSizeAfter = PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.Memory.ZeroFill(lastPageFillAddr, unusedSizeAfter);
|
_context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter);
|
||||||
|
|
||||||
if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success)
|
if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -1897,7 +1898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
private KernelResult MapPagesFromAnotherProcess(
|
private KernelResult MapPagesFromAnotherProcess(
|
||||||
ulong size,
|
ulong size,
|
||||||
ulong address,
|
ulong address,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
KPageList pageList,
|
KPageList pageList,
|
||||||
out ulong dst)
|
out ulong dst)
|
||||||
|
@ -1975,8 +1976,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
state,
|
state,
|
||||||
MemoryPermission.Read,
|
KMemoryPermission.Read,
|
||||||
MemoryPermission.Read,
|
KMemoryPermission.Read,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -1996,14 +1997,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
|
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
|
||||||
|
|
||||||
KernelResult result = DoMmuOperation(
|
|
||||||
addressTruncated,
|
|
||||||
pagesCount,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
MemoryPermission.None,
|
|
||||||
MemoryOperation.Unmap);
|
|
||||||
|
|
||||||
// Free pages we had to create on-demand, if any of the buffer was not page aligned.
|
// Free pages we had to create on-demand, if any of the buffer was not page aligned.
|
||||||
// Real kernel has page ref counting, so this is done as part of the unmap operation.
|
// Real kernel has page ref counting, so this is done as part of the unmap operation.
|
||||||
if (addressTruncated != addressRounded)
|
if (addressTruncated != addressRounded)
|
||||||
|
@ -2016,6 +2009,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated));
|
FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KernelResult result = DoMmuOperation(
|
||||||
|
addressTruncated,
|
||||||
|
pagesCount,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
KMemoryPermission.None,
|
||||||
|
MemoryOperation.Unmap);
|
||||||
|
|
||||||
if (result == KernelResult.Success)
|
if (result == KernelResult.Success)
|
||||||
{
|
{
|
||||||
InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
|
InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
|
||||||
|
@ -2037,7 +2038,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong addressRounded = BitUtils.AlignUp (address, PageSize);
|
ulong addressRounded = BitUtils.AlignUp (address, PageSize);
|
||||||
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
|
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
|
||||||
|
|
||||||
ulong pagesCount = (endAddrTruncated - addressRounded) / PageSize;
|
ulong pagesCount = addressRounded < endAddrTruncated ? (endAddrTruncated - addressRounded) / PageSize : 0;
|
||||||
|
|
||||||
|
if (pagesCount == 0)
|
||||||
|
{
|
||||||
|
return KernelResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
MemoryState stateMask;
|
MemoryState stateMask;
|
||||||
|
|
||||||
|
@ -2111,23 +2117,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.IpcBufferAllowed,
|
MemoryState.IpcBufferAllowed,
|
||||||
MemoryState.IpcBufferAllowed,
|
MemoryState.IpcBufferAllowed,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Borrowed);
|
MemoryAttribute.Borrowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, MemoryPermission permission)
|
public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
return SetAttributesAndChangePermission(
|
return SetAttributesAndChangePermission(
|
||||||
address,
|
address,
|
||||||
size,
|
size,
|
||||||
MemoryState.TransferMemoryAllowed,
|
MemoryState.TransferMemoryAllowed,
|
||||||
MemoryState.TransferMemoryAllowed,
|
MemoryState.TransferMemoryAllowed,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
permission,
|
permission,
|
||||||
|
@ -2140,11 +2146,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permissionMask,
|
KMemoryPermission permissionMask,
|
||||||
MemoryPermission permissionExpected,
|
KMemoryPermission permissionExpected,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected,
|
MemoryAttribute attributeExpected,
|
||||||
MemoryPermission newPermission,
|
KMemoryPermission newPermission,
|
||||||
MemoryAttribute attributeSetMask,
|
MemoryAttribute attributeSetMask,
|
||||||
KPageList pageList = null)
|
KPageList pageList = null)
|
||||||
{
|
{
|
||||||
|
@ -2166,7 +2172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
attributeExpected,
|
attributeExpected,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
out MemoryState oldState,
|
out MemoryState oldState,
|
||||||
out MemoryPermission oldPermission,
|
out KMemoryPermission oldPermission,
|
||||||
out MemoryAttribute oldAttribute))
|
out MemoryAttribute oldAttribute))
|
||||||
{
|
{
|
||||||
ulong pagesCount = size / PageSize;
|
ulong pagesCount = size / PageSize;
|
||||||
|
@ -2181,7 +2187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return KernelResult.OutOfResource;
|
return KernelResult.OutOfResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPermission == MemoryPermission.None)
|
if (newPermission == KMemoryPermission.None)
|
||||||
{
|
{
|
||||||
newPermission = oldPermission;
|
newPermission = oldPermission;
|
||||||
}
|
}
|
||||||
|
@ -2222,11 +2228,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.IpcBufferAllowed,
|
MemoryState.IpcBufferAllowed,
|
||||||
MemoryState.IpcBufferAllowed,
|
MemoryState.IpcBufferAllowed,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.Borrowed,
|
MemoryAttribute.Borrowed,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Borrowed);
|
MemoryAttribute.Borrowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2237,11 +2243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.TransferMemoryAllowed,
|
MemoryState.TransferMemoryAllowed,
|
||||||
MemoryState.TransferMemoryAllowed,
|
MemoryState.TransferMemoryAllowed,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.Borrowed,
|
MemoryAttribute.Borrowed,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
MemoryAttribute.Borrowed,
|
MemoryAttribute.Borrowed,
|
||||||
pageList);
|
pageList);
|
||||||
}
|
}
|
||||||
|
@ -2251,11 +2257,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permissionMask,
|
KMemoryPermission permissionMask,
|
||||||
MemoryPermission permissionExpected,
|
KMemoryPermission permissionExpected,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected,
|
MemoryAttribute attributeExpected,
|
||||||
MemoryPermission newPermission,
|
KMemoryPermission newPermission,
|
||||||
MemoryAttribute attributeClearMask,
|
MemoryAttribute attributeClearMask,
|
||||||
KPageList pageList = null)
|
KPageList pageList = null)
|
||||||
{
|
{
|
||||||
|
@ -2277,7 +2283,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
attributeExpected,
|
attributeExpected,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
out MemoryState oldState,
|
out MemoryState oldState,
|
||||||
out MemoryPermission oldPermission,
|
out KMemoryPermission oldPermission,
|
||||||
out MemoryAttribute oldAttribute))
|
out MemoryAttribute oldAttribute))
|
||||||
{
|
{
|
||||||
ulong pagesCount = size / PageSize;
|
ulong pagesCount = size / PageSize;
|
||||||
|
@ -2299,7 +2305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return KernelResult.OutOfResource;
|
return KernelResult.OutOfResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPermission == MemoryPermission.None)
|
if (newPermission == KMemoryPermission.None)
|
||||||
{
|
{
|
||||||
newPermission = oldPermission;
|
newPermission = oldPermission;
|
||||||
}
|
}
|
||||||
|
@ -2385,8 +2391,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
size,
|
size,
|
||||||
MemoryState.Mask,
|
MemoryState.Mask,
|
||||||
MemoryState.Unmapped,
|
MemoryState.Unmapped,
|
||||||
MemoryPermission.Mask,
|
KMemoryPermission.Mask,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped,
|
||||||
|
@ -2400,13 +2406,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permissionMask,
|
KMemoryPermission permissionMask,
|
||||||
MemoryPermission permissionExpected,
|
KMemoryPermission permissionExpected,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected,
|
MemoryAttribute attributeExpected,
|
||||||
MemoryAttribute attributeIgnoreMask,
|
MemoryAttribute attributeIgnoreMask,
|
||||||
out MemoryState outState,
|
out MemoryState outState,
|
||||||
out MemoryPermission outPermission,
|
out KMemoryPermission outPermission,
|
||||||
out MemoryAttribute outAttribute)
|
out MemoryAttribute outAttribute)
|
||||||
{
|
{
|
||||||
ulong endAddr = address + size;
|
ulong endAddr = address + size;
|
||||||
|
@ -2416,7 +2422,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
KMemoryInfo info = node.Value.GetInfo();
|
KMemoryInfo info = node.Value.GetInfo();
|
||||||
|
|
||||||
MemoryState firstState = info.State;
|
MemoryState firstState = info.State;
|
||||||
MemoryPermission firstPermission = info.Permission;
|
KMemoryPermission firstPermission = info.Permission;
|
||||||
MemoryAttribute firstAttribute = info.Attribute;
|
MemoryAttribute firstAttribute = info.Attribute;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -2432,7 +2438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
(firstPermission & permissionMask) != permissionExpected)
|
(firstPermission & permissionMask) != permissionExpected)
|
||||||
{
|
{
|
||||||
outState = MemoryState.Unmapped;
|
outState = MemoryState.Unmapped;
|
||||||
outPermission = MemoryPermission.None;
|
outPermission = KMemoryPermission.None;
|
||||||
outAttribute = MemoryAttribute.None;
|
outAttribute = MemoryAttribute.None;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2452,8 +2458,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong size,
|
ulong size,
|
||||||
MemoryState stateMask,
|
MemoryState stateMask,
|
||||||
MemoryState stateExpected,
|
MemoryState stateExpected,
|
||||||
MemoryPermission permissionMask,
|
KMemoryPermission permissionMask,
|
||||||
MemoryPermission permissionExpected,
|
KMemoryPermission permissionExpected,
|
||||||
MemoryAttribute attributeMask,
|
MemoryAttribute attributeMask,
|
||||||
MemoryAttribute attributeExpected)
|
MemoryAttribute attributeExpected)
|
||||||
{
|
{
|
||||||
|
@ -2490,10 +2496,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong baseAddress,
|
ulong baseAddress,
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
MemoryState oldState,
|
MemoryState oldState,
|
||||||
MemoryPermission oldPermission,
|
KMemoryPermission oldPermission,
|
||||||
MemoryAttribute oldAttribute,
|
MemoryAttribute oldAttribute,
|
||||||
MemoryState newState,
|
MemoryState newState,
|
||||||
MemoryPermission newPermission,
|
KMemoryPermission newPermission,
|
||||||
MemoryAttribute newAttribute)
|
MemoryAttribute newAttribute)
|
||||||
{
|
{
|
||||||
// Insert new block on the list only on areas where the state
|
// Insert new block on the list only on areas where the state
|
||||||
|
@ -2553,13 +2559,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
_blockAllocator.Count += _blocks.Count - oldCount;
|
_blockAllocator.Count += _blocks.Count - oldCount;
|
||||||
|
|
||||||
|
ValidateInternalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InsertBlock(
|
private void InsertBlock(
|
||||||
ulong baseAddress,
|
ulong baseAddress,
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
MemoryState state,
|
MemoryState state,
|
||||||
MemoryPermission permission = MemoryPermission.None,
|
KMemoryPermission permission = KMemoryPermission.None,
|
||||||
MemoryAttribute attribute = MemoryAttribute.None)
|
MemoryAttribute attribute = MemoryAttribute.None)
|
||||||
{
|
{
|
||||||
// Inserts new block at the list, replacing and splitting
|
// Inserts new block at the list, replacing and splitting
|
||||||
|
@ -2605,25 +2613,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
_blockAllocator.Count += _blocks.Count - oldCount;
|
_blockAllocator.Count += _blocks.Count - oldCount;
|
||||||
|
|
||||||
|
ValidateInternalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
|
private static void SetIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
block.SetIpcMappingPermission(permission);
|
block.SetIpcMappingPermission(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RestoreIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
|
private static void RestoreIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
block.RestoreIpcMappingPermission();
|
block.RestoreIpcMappingPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate void BlockMutator(KMemoryBlock block, MemoryPermission newPerm);
|
private delegate void BlockMutator(KMemoryBlock block, KMemoryPermission newPerm);
|
||||||
|
|
||||||
private void InsertBlock(
|
private void InsertBlock(
|
||||||
ulong baseAddress,
|
ulong baseAddress,
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
BlockMutator blockMutate,
|
BlockMutator blockMutate,
|
||||||
MemoryPermission permission = MemoryPermission.None)
|
KMemoryPermission permission = KMemoryPermission.None)
|
||||||
{
|
{
|
||||||
// Inserts new block at the list, replacing and splitting
|
// Inserts new block at the list, replacing and splitting
|
||||||
// existing blocks as needed, then calling the callback
|
// existing blocks as needed, then calling the callback
|
||||||
|
@ -2671,6 +2681,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
_blockAllocator.Count += _blocks.Count - oldCount;
|
_blockAllocator.Count += _blocks.Count - oldCount;
|
||||||
|
|
||||||
|
ValidateInternalState();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
private void ValidateInternalState()
|
||||||
|
{
|
||||||
|
ulong expectedAddress = 0;
|
||||||
|
|
||||||
|
LinkedListNode<KMemoryBlock> node = _blocks.First;
|
||||||
|
|
||||||
|
while (node != null)
|
||||||
|
{
|
||||||
|
LinkedListNode<KMemoryBlock> newNode = node;
|
||||||
|
|
||||||
|
KMemoryBlock currBlock = node.Value;
|
||||||
|
|
||||||
|
Debug.Assert(currBlock.BaseAddress == expectedAddress);
|
||||||
|
|
||||||
|
expectedAddress = currBlock.BaseAddress + currBlock.PagesCount * PageSize;
|
||||||
|
|
||||||
|
node = newNode.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(expectedAddress == AddrSpaceEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node)
|
private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node)
|
||||||
|
@ -2876,13 +2911,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateRegionForState(ulong address, ulong size, MemoryState state)
|
public bool CanContain(ulong address, ulong size, MemoryState state)
|
||||||
{
|
{
|
||||||
ulong endAddr = address + size;
|
ulong endAddr = address + size;
|
||||||
|
|
||||||
ulong regionBaseAddr = GetBaseAddrForState(state);
|
ulong regionBaseAddr = GetBaseAddress(state);
|
||||||
|
ulong regionEndAddr = regionBaseAddr + GetSize(state);
|
||||||
ulong regionEndAddr = regionBaseAddr + GetSizeForState(state);
|
|
||||||
|
|
||||||
bool InsideRegion()
|
bool InsideRegion()
|
||||||
{
|
{
|
||||||
|
@ -2891,17 +2925,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
endAddr - 1 <= regionEndAddr - 1;
|
endAddr - 1 <= regionEndAddr - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OutsideHeapRegion()
|
bool OutsideHeapRegion() => endAddr <= HeapRegionStart || address >= HeapRegionEnd;
|
||||||
{
|
bool OutsideAliasRegion() => endAddr <= AliasRegionStart || address >= AliasRegionEnd;
|
||||||
return endAddr <= HeapRegionStart ||
|
|
||||||
address >= HeapRegionEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OutsideMapRegion()
|
|
||||||
{
|
|
||||||
return endAddr <= AliasRegionStart ||
|
|
||||||
address >= AliasRegionEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
@ -2919,10 +2944,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
case MemoryState.ProcessMemory:
|
case MemoryState.ProcessMemory:
|
||||||
case MemoryState.CodeReadOnly:
|
case MemoryState.CodeReadOnly:
|
||||||
case MemoryState.CodeWritable:
|
case MemoryState.CodeWritable:
|
||||||
return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion();
|
return InsideRegion() && OutsideHeapRegion() && OutsideAliasRegion();
|
||||||
|
|
||||||
case MemoryState.Heap:
|
case MemoryState.Heap:
|
||||||
return InsideRegion() && OutsideMapRegion();
|
return InsideRegion() && OutsideAliasRegion();
|
||||||
|
|
||||||
case MemoryState.IpcBuffer0:
|
case MemoryState.IpcBuffer0:
|
||||||
case MemoryState.IpcBuffer1:
|
case MemoryState.IpcBuffer1:
|
||||||
|
@ -2936,7 +2961,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
throw new ArgumentException($"Invalid state value \"{state}\".");
|
throw new ArgumentException($"Invalid state value \"{state}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong GetBaseAddrForState(MemoryState state)
|
private ulong GetBaseAddress(MemoryState state)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
@ -2975,7 +3000,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
throw new ArgumentException($"Invalid state value \"{state}\".");
|
throw new ArgumentException($"Invalid state value \"{state}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong GetSizeForState(MemoryState state)
|
private ulong GetSize(MemoryState state)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
@ -3050,7 +3075,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private KernelResult MapPages(ulong address, KPageList pageList, MemoryPermission permission)
|
private KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong currAddr = address;
|
ulong currAddr = address;
|
||||||
|
|
||||||
|
@ -3090,11 +3115,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
pagesCount,
|
pagesCount,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
MemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryOperation.Unmap);
|
MemoryOperation.Unmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission)
|
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
return DoMmuOperation(
|
return DoMmuOperation(
|
||||||
address,
|
address,
|
||||||
|
@ -3110,7 +3135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
ulong srcPa,
|
ulong srcPa,
|
||||||
bool map,
|
bool map,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryOperation operation)
|
MemoryOperation operation)
|
||||||
{
|
{
|
||||||
if (map != (operation == MemoryOperation.MapPa))
|
if (map != (operation == MemoryOperation.MapPa))
|
||||||
|
@ -3171,7 +3196,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong pagesCount,
|
ulong pagesCount,
|
||||||
KPageList pageList,
|
KPageList pageList,
|
||||||
MemoryPermission permission,
|
KMemoryPermission permission,
|
||||||
MemoryOperation operation)
|
MemoryOperation operation)
|
||||||
{
|
{
|
||||||
if (operation != MemoryOperation.MapVa)
|
if (operation != MemoryOperation.MapVa)
|
||||||
|
|
|
@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
private readonly long _ownerPid;
|
private readonly long _ownerPid;
|
||||||
|
|
||||||
private readonly MemoryPermission _ownerPermission;
|
private readonly KMemoryPermission _ownerPermission;
|
||||||
private readonly MemoryPermission _userPermission;
|
private readonly KMemoryPermission _userPermission;
|
||||||
|
|
||||||
public KSharedMemory(
|
public KSharedMemory(
|
||||||
KernelContext context,
|
KernelContext context,
|
||||||
KPageList pageList,
|
KPageList pageList,
|
||||||
long ownerPid,
|
long ownerPid,
|
||||||
MemoryPermission ownerPermission,
|
KMemoryPermission ownerPermission,
|
||||||
MemoryPermission userPermission) : base(context)
|
KMemoryPermission userPermission) : base(context)
|
||||||
{
|
{
|
||||||
_pageList = pageList;
|
_pageList = pageList;
|
||||||
_ownerPid = ownerPid;
|
_ownerPid = ownerPid;
|
||||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong size,
|
ulong size,
|
||||||
KProcess process,
|
KProcess process,
|
||||||
MemoryPermission permission)
|
KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
|
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return KernelResult.InvalidSize;
|
return KernelResult.InvalidSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPermission expectedPermission = process.Pid == _ownerPid
|
KMemoryPermission expectedPermission = process.Pid == _ownerPid
|
||||||
? _ownerPermission
|
? _ownerPermission
|
||||||
: _userPermission;
|
: _userPermission;
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
private KProcess _creator;
|
private KProcess _creator;
|
||||||
|
|
||||||
|
// TODO: Remove when we no longer need to read it from the owner directly.
|
||||||
|
public KProcess Creator => _creator;
|
||||||
|
|
||||||
private readonly KPageList _pageList;
|
private readonly KPageList _pageList;
|
||||||
|
|
||||||
public ulong Address { get; private set; }
|
public ulong Address { get; private set; }
|
||||||
public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize;
|
public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize;
|
||||||
|
|
||||||
public MemoryPermission Permission { get; private set; }
|
public KMemoryPermission Permission { get; private set; }
|
||||||
|
|
||||||
private bool _hasBeenInitialized;
|
private bool _hasBeenInitialized;
|
||||||
private bool _isMapped;
|
private bool _isMapped;
|
||||||
|
@ -23,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
_pageList = new KPageList();
|
_pageList = new KPageList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult Initialize(ulong address, ulong size, MemoryPermission permission)
|
public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
KProcess creator = KernelContext.Scheduler.GetCurrentProcess();
|
KProcess creator = KernelContext.Scheduler.GetCurrentProcess();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
enum MemoryPermission : byte
|
enum KMemoryPermission : byte
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
Mask = 0xff,
|
Mask = 0xff,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Ryujinx.Cpu;
|
|
||||||
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.Loaders.Elf;
|
using Ryujinx.HLE.Loaders.Elf;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute)
|
if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute)
|
||||||
{
|
{
|
||||||
LoadMod0Symbols(_owner.CpuMemory, info.Address);
|
LoadMod0Symbols(_owner.CpuMemory, info.Address);
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadMod0Symbols(MemoryManager memory, ulong textOffset)
|
private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset)
|
||||||
{
|
{
|
||||||
ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4);
|
ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4);
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ElfSymbol GetSymbol64(MemoryManager memory, ulong address, ulong strTblAddr)
|
private ElfSymbol GetSymbol64(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
|
||||||
{
|
{
|
||||||
ElfSymbol64 sym = memory.Read<ElfSymbol64>(address);
|
ElfSymbol64 sym = memory.Read<ElfSymbol64>(address);
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
|
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ElfSymbol GetSymbol32(MemoryManager memory, ulong address, ulong strTblAddr)
|
private ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
|
||||||
{
|
{
|
||||||
ElfSymbol32 sym = memory.Read<ElfSymbol32>(address);
|
ElfSymbol32 sym = memory.Read<ElfSymbol32>(address);
|
||||||
|
|
||||||
|
|
13
Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
Normal file
13
Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
{
|
||||||
|
interface IProcessContext : IDisposable
|
||||||
|
{
|
||||||
|
IVirtualMemoryManager AddressSpace { get; }
|
||||||
|
|
||||||
|
void Execute(ExecutionContext context, ulong codeAddress);
|
||||||
|
}
|
||||||
|
}
|
10
Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
Normal file
10
Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
{
|
||||||
|
interface IProcessContextFactory
|
||||||
|
{
|
||||||
|
IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
class KProcess : KSynchronizationObject
|
class KProcess : KSynchronizationObject
|
||||||
{
|
{
|
||||||
public const int KernelVersionMajor = 10;
|
public const int KernelVersionMajor = 10;
|
||||||
public const int KernelVersionMinor = 4;
|
public const int KernelVersionMinor = 4;
|
||||||
public const int KernelVersionRevision = 0;
|
public const int KernelVersionRevision = 0;
|
||||||
|
|
||||||
public const int KernelVersionPacked =
|
public const int KernelVersionPacked =
|
||||||
(KernelVersionMajor << 19) |
|
(KernelVersionMajor << 19) |
|
||||||
(KernelVersionMinor << 15) |
|
(KernelVersionMinor << 15) |
|
||||||
(KernelVersionRevision << 0);
|
(KernelVersionRevision << 0);
|
||||||
|
|
||||||
public KMemoryManager MemoryManager { get; private set; }
|
public KMemoryManager MemoryManager { get; private set; }
|
||||||
|
@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
public long[] RandomEntropy { get; private set; }
|
public long[] RandomEntropy { get; private set; }
|
||||||
|
|
||||||
private bool _signaled;
|
private bool _signaled;
|
||||||
private bool _useSystemMemBlocks;
|
|
||||||
|
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
private int _threadCount;
|
private int _threadCount;
|
||||||
|
|
||||||
public int MmuFlags { get; private set; }
|
public ProcessCreationFlags Flags { get; private set; }
|
||||||
|
|
||||||
private MemoryRegion _memRegion;
|
private MemoryRegion _memRegion;
|
||||||
|
|
||||||
public KProcessCapabilities Capabilities { get; private set; }
|
public KProcessCapabilities Capabilities { get; private set; }
|
||||||
|
|
||||||
public ulong TitleId { get; private set; }
|
public ulong TitleId { get; private set; }
|
||||||
public long Pid { get; private set; }
|
public long Pid { get; private set; }
|
||||||
|
|
||||||
private long _creationTimestamp;
|
private long _creationTimestamp;
|
||||||
private ulong _entrypoint;
|
private ulong _entrypoint;
|
||||||
|
private ThreadStart _customThreadStart;
|
||||||
private ulong _imageSize;
|
private ulong _imageSize;
|
||||||
private ulong _mainThreadStackSize;
|
private ulong _mainThreadStackSize;
|
||||||
private ulong _memoryUsageCapacity;
|
private ulong _memoryUsageCapacity;
|
||||||
private int _version;
|
private int _version;
|
||||||
|
|
||||||
public KHandleTable HandleTable { get; private set; }
|
public KHandleTable HandleTable { get; private set; }
|
||||||
|
|
||||||
|
@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
public bool IsPaused { get; private set; }
|
public bool IsPaused { get; private set; }
|
||||||
|
|
||||||
public MemoryManager CpuMemory { get; private set; }
|
private IProcessContextFactory _contextFactory;
|
||||||
public CpuContext CpuContext { get; private set; }
|
public IProcessContext Context { get; private set; }
|
||||||
|
public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
|
||||||
|
|
||||||
public HleProcessDebugger Debugger { get; private set; }
|
public HleProcessDebugger Debugger { get; private set; }
|
||||||
|
|
||||||
public KProcess(KernelContext context) : base(context)
|
public KProcess(KernelContext context) : base(context)
|
||||||
{
|
{
|
||||||
_processLock = new object();
|
_processLock = new object();
|
||||||
_threadingLock = new object();
|
_threadingLock = new object();
|
||||||
|
|
||||||
AddressArbiter = new KAddressArbiter(context);
|
AddressArbiter = new KAddressArbiter(context);
|
||||||
|
@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
||||||
|
|
||||||
|
// TODO: Remove once we no longer need to initialize it externally.
|
||||||
|
HandleTable = new KHandleTable(context);
|
||||||
|
|
||||||
_threads = new LinkedList<KThread>();
|
_threads = new LinkedList<KThread>();
|
||||||
|
|
||||||
Debugger = new HleProcessDebugger(this);
|
Debugger = new HleProcessDebugger(this);
|
||||||
|
@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
public KernelResult InitializeKip(
|
public KernelResult InitializeKip(
|
||||||
ProcessCreationInfo creationInfo,
|
ProcessCreationInfo creationInfo,
|
||||||
int[] caps,
|
ReadOnlySpan<int> capabilities,
|
||||||
KPageList pageList,
|
KPageList pageList,
|
||||||
KResourceLimit resourceLimit,
|
KResourceLimit resourceLimit,
|
||||||
MemoryRegion memRegion)
|
MemoryRegion memRegion,
|
||||||
|
IProcessContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
ResourceLimit = resourceLimit;
|
ResourceLimit = resourceLimit;
|
||||||
_memRegion = memRegion;
|
_memRegion = memRegion;
|
||||||
|
_contextFactory = contextFactory ?? new ProcessContextFactory();
|
||||||
|
|
||||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7);
|
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
||||||
|
|
||||||
InitializeMemoryManager(addrSpaceType, memRegion);
|
InitializeMemoryManager(creationInfo.Flags);
|
||||||
|
|
||||||
bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0;
|
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||||
|
|
||||||
ulong codeAddress = creationInfo.CodeAddress;
|
ulong codeAddress = creationInfo.CodeAddress;
|
||||||
|
|
||||||
ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||||
|
|
||||||
KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0
|
KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
|
||||||
? KernelContext.LargeMemoryBlockAllocator
|
? KernelContext.LargeMemoryBlockAllocator
|
||||||
: KernelContext.SmallMemoryBlockAllocator;
|
: KernelContext.SmallMemoryBlockAllocator;
|
||||||
|
|
||||||
|
@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
|
if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidMemRange;
|
return KernelResult.InvalidMemRange;
|
||||||
}
|
}
|
||||||
|
@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
codeAddress,
|
codeAddress,
|
||||||
pageList,
|
pageList,
|
||||||
MemoryState.CodeStatic,
|
MemoryState.CodeStatic,
|
||||||
MemoryPermission.None);
|
KMemoryPermission.None);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Capabilities.InitializeForKernel(caps, MemoryManager);
|
result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
public KernelResult Initialize(
|
public KernelResult Initialize(
|
||||||
ProcessCreationInfo creationInfo,
|
ProcessCreationInfo creationInfo,
|
||||||
int[] caps,
|
ReadOnlySpan<int> capabilities,
|
||||||
KResourceLimit resourceLimit,
|
KResourceLimit resourceLimit,
|
||||||
MemoryRegion memRegion)
|
MemoryRegion memRegion,
|
||||||
|
IProcessContextFactory contextFactory,
|
||||||
|
ThreadStart customThreadStart = null)
|
||||||
{
|
{
|
||||||
ResourceLimit = resourceLimit;
|
ResourceLimit = resourceLimit;
|
||||||
_memRegion = memRegion;
|
_memRegion = memRegion;
|
||||||
|
_contextFactory = contextFactory ?? new ProcessContextFactory();
|
||||||
|
|
||||||
ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.PersonalMmHeapPagesCount, memRegion);
|
ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion);
|
||||||
|
|
||||||
ulong codePagesCount = (ulong)creationInfo.CodePagesCount;
|
ulong codePagesCount = (ulong)creationInfo.CodePagesCount;
|
||||||
|
|
||||||
|
@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount;
|
PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount;
|
||||||
|
|
||||||
KMemoryBlockAllocator memoryBlockAllocator;
|
KMemoryBlockAllocator memoryBlockAllocator;
|
||||||
|
|
||||||
|
@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memoryBlockAllocator = (MmuFlags & 0x40) != 0
|
memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
|
||||||
? KernelContext.LargeMemoryBlockAllocator
|
? KernelContext.LargeMemoryBlockAllocator
|
||||||
: KernelContext.SmallMemoryBlockAllocator;
|
: KernelContext.SmallMemoryBlockAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7);
|
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
||||||
|
|
||||||
InitializeMemoryManager(addrSpaceType, memRegion);
|
InitializeMemoryManager(creationInfo.Flags);
|
||||||
|
|
||||||
bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0;
|
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||||
|
|
||||||
ulong codeAddress = creationInfo.CodeAddress;
|
ulong codeAddress = creationInfo.CodeAddress;
|
||||||
|
|
||||||
|
@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
|
if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
|
||||||
{
|
{
|
||||||
CleanUpForError();
|
CleanUpForError();
|
||||||
|
|
||||||
|
@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
codeAddress,
|
codeAddress,
|
||||||
codePagesCount,
|
codePagesCount,
|
||||||
MemoryState.CodeStatic,
|
MemoryState.CodeStatic,
|
||||||
MemoryPermission.None);
|
KMemoryPermission.None);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Capabilities.InitializeForUser(caps, MemoryManager);
|
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
CleanUpForError();
|
CleanUpForError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_customThreadStart = customThreadStart;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateCodeAddressAndSize(ulong address, ulong size)
|
|
||||||
{
|
|
||||||
ulong codeRegionStart;
|
|
||||||
ulong codeRegionSize;
|
|
||||||
|
|
||||||
switch (MemoryManager.AddrSpaceWidth)
|
|
||||||
{
|
|
||||||
case 32:
|
|
||||||
codeRegionStart = 0x200000;
|
|
||||||
codeRegionSize = 0x3fe00000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 36:
|
|
||||||
codeRegionStart = 0x8000000;
|
|
||||||
codeRegionSize = 0x78000000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 39:
|
|
||||||
codeRegionStart = 0x8000000;
|
|
||||||
codeRegionSize = 0x7ff8000000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new InvalidOperationException("Invalid address space width on memory manager.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong endAddr = address + size;
|
|
||||||
|
|
||||||
ulong codeRegionEnd = codeRegionStart + codeRegionSize;
|
|
||||||
|
|
||||||
if (endAddr <= address ||
|
|
||||||
endAddr - 1 > codeRegionEnd - 1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MemoryManager.InsideHeapRegion (address, size) ||
|
|
||||||
MemoryManager.InsideAliasRegion(address, size))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
|
private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
|
||||||
{
|
{
|
||||||
// Ensure that the current kernel version is equal or above to the minimum required.
|
// Ensure that the current kernel version is equal or above to the minimum required.
|
||||||
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
|
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
|
||||||
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
|
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
|
||||||
|
|
||||||
if (KernelContext.EnableVersionChecks)
|
if (KernelContext.EnableVersionChecks)
|
||||||
|
@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
|
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
|
||||||
|
|
||||||
MmuFlags = creationInfo.MmuFlags;
|
Flags = creationInfo.Flags;
|
||||||
_version = creationInfo.Version;
|
_version = creationInfo.Version;
|
||||||
TitleId = creationInfo.TitleId;
|
TitleId = creationInfo.TitleId;
|
||||||
_entrypoint = creationInfo.CodeAddress;
|
_entrypoint = creationInfo.CodeAddress;
|
||||||
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||||
|
|
||||||
_useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0;
|
switch (Flags & ProcessCreationFlags.AddressSpaceMask)
|
||||||
|
|
||||||
switch ((AddressSpaceType)((MmuFlags >> 1) & 7))
|
|
||||||
{
|
{
|
||||||
case AddressSpaceType.Addr32Bits:
|
case ProcessCreationFlags.AddressSpace32Bit:
|
||||||
case AddressSpaceType.Addr36Bits:
|
case ProcessCreationFlags.AddressSpace64BitDeprecated:
|
||||||
case AddressSpaceType.Addr39Bits:
|
case ProcessCreationFlags.AddressSpace64Bit:
|
||||||
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
||||||
MemoryManager.HeapRegionStart;
|
MemoryManager.HeapRegionStart;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr32BitsNoMap:
|
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
|
||||||
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
||||||
MemoryManager.HeapRegionStart +
|
MemoryManager.HeapRegionStart +
|
||||||
MemoryManager.AliasRegionEnd -
|
MemoryManager.AliasRegionEnd -
|
||||||
MemoryManager.AliasRegionStart;
|
MemoryManager.AliasRegionStart;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}.");
|
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateRandomEntropy();
|
GenerateRandomEntropy();
|
||||||
|
@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong regionStart = MemoryManager.TlsIoRegionStart;
|
ulong regionStart = MemoryManager.TlsIoRegionStart;
|
||||||
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
|
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
|
||||||
|
|
||||||
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
||||||
|
|
||||||
|
@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
regionStart,
|
regionStart,
|
||||||
regionPagesCount,
|
regionPagesCount,
|
||||||
MemoryState.ThreadLocal,
|
MemoryState.ThreadLocal,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
out ulong tlsPageVa);
|
out ulong tlsPageVa);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
|
@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
KernelResult result = KernelResult.Success;
|
KernelResult result = KernelResult.Success;
|
||||||
|
|
||||||
KTlsPageInfo pageInfo = null;
|
KTlsPageInfo pageInfo;
|
||||||
|
|
||||||
if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
|
if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
|
||||||
{
|
{
|
||||||
|
@ -594,8 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
// Check if the needed size for the code and the stack will fit on the
|
// Check if the needed size for the code and the stack will fit on the
|
||||||
// memory usage capacity of this Process. Also check for possible overflow
|
// memory usage capacity of this Process. Also check for possible overflow
|
||||||
// on the above addition.
|
// on the above addition.
|
||||||
if (neededSize > _memoryUsageCapacity ||
|
if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
|
||||||
neededSize < stackSizeRounded)
|
|
||||||
{
|
{
|
||||||
threadResourceLimit?.Release(LimitableResource.Thread, 1);
|
threadResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||||
|
|
||||||
|
@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;
|
ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;
|
||||||
|
|
||||||
ulong regionStart = MemoryManager.StackRegionStart;
|
ulong regionStart = MemoryManager.StackRegionStart;
|
||||||
ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
|
ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
|
||||||
|
|
||||||
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
||||||
|
|
||||||
|
@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
regionStart,
|
regionStart,
|
||||||
regionPagesCount,
|
regionPagesCount,
|
||||||
MemoryState.Stack,
|
MemoryState.Stack,
|
||||||
MemoryPermission.ReadAndWrite,
|
KMemoryPermission.ReadAndWrite,
|
||||||
out ulong stackBottom);
|
out ulong stackBottom);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
|
@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
stackTop,
|
stackTop,
|
||||||
mainThreadPriority,
|
mainThreadPriority,
|
||||||
DefaultCpuCore,
|
DefaultCpuCore,
|
||||||
this);
|
this,
|
||||||
|
ThreadType.User,
|
||||||
|
_customThreadStart);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
SetState(newState);
|
SetState(newState);
|
||||||
|
|
||||||
// TODO: We can't call KThread.Start from a non-guest thread.
|
result = mainThread.Start();
|
||||||
// We will need to make some changes to allow the creation of
|
|
||||||
// dummy threads that will be used to initialize the current
|
|
||||||
// thread on KCoreContext so that GetCurrentThread doesn't fail.
|
|
||||||
/* Result = MainThread.Start();
|
|
||||||
|
|
||||||
if (Result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
SetState(OldState);
|
SetState(oldState);
|
||||||
|
|
||||||
CleanUpForError();
|
CleanUpForError();
|
||||||
} */
|
}
|
||||||
|
|
||||||
mainThread.Reschedule(ThreadSchedState.Running);
|
|
||||||
|
|
||||||
if (result == KernelResult.Success)
|
if (result == KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
if (State != newState)
|
if (State != newState)
|
||||||
{
|
{
|
||||||
State = newState;
|
State = newState;
|
||||||
_signaled = true;
|
_signaled = true;
|
||||||
|
|
||||||
Signal();
|
Signal();
|
||||||
|
@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
public KernelResult InitializeThread(
|
public KernelResult InitializeThread(
|
||||||
KThread thread,
|
KThread thread,
|
||||||
ulong entrypoint,
|
ulong entrypoint,
|
||||||
ulong argsPtr,
|
ulong argsPtr,
|
||||||
ulong stackTop,
|
ulong stackTop,
|
||||||
int priority,
|
int priority,
|
||||||
int cpuCore)
|
int cpuCore)
|
||||||
{
|
{
|
||||||
lock (_processLock)
|
lock (_processLock)
|
||||||
{
|
{
|
||||||
return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this);
|
return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
|
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
|
||||||
{
|
{
|
||||||
context.Interrupt += InterruptHandler;
|
context.Interrupt += InterruptHandler;
|
||||||
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
|
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
|
||||||
context.Undefined += UndefinedInstructionHandler;
|
context.Undefined += UndefinedInstructionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InterruptHandler(object sender, EventArgs e)
|
private void InterruptHandler(object sender, EventArgs e)
|
||||||
|
@ -910,8 +871,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
if (State >= ProcessState.Started)
|
if (State >= ProcessState.Started)
|
||||||
{
|
{
|
||||||
if (State == ProcessState.Started ||
|
if (State == ProcessState.Started ||
|
||||||
State == ProcessState.Crashed ||
|
State == ProcessState.Crashed ||
|
||||||
State == ProcessState.Attached ||
|
State == ProcessState.Attached ||
|
||||||
State == ProcessState.DebugSuspended)
|
State == ProcessState.DebugSuspended)
|
||||||
{
|
{
|
||||||
|
@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion)
|
private void InitializeMemoryManager(ProcessCreationFlags flags)
|
||||||
{
|
{
|
||||||
int addrSpaceBits = addrSpaceType switch
|
int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch
|
||||||
{
|
{
|
||||||
AddressSpaceType.Addr32Bits => 32,
|
ProcessCreationFlags.AddressSpace32Bit => 32,
|
||||||
AddressSpaceType.Addr36Bits => 36,
|
ProcessCreationFlags.AddressSpace64BitDeprecated => 36,
|
||||||
AddressSpaceType.Addr32BitsNoMap => 32,
|
ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32,
|
||||||
AddressSpaceType.Addr39Bits => 39,
|
ProcessCreationFlags.AddressSpace64Bit => 39,
|
||||||
_ => throw new ArgumentException(nameof(addrSpaceType))
|
_ => 39
|
||||||
};
|
};
|
||||||
|
|
||||||
CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
|
Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
|
||||||
CpuContext = new CpuContext(CpuMemory);
|
|
||||||
|
|
||||||
// TODO: This should eventually be removed.
|
// TODO: This should eventually be removed.
|
||||||
// The GPU shouldn't depend on the CPU memory manager at all.
|
// The GPU shouldn't depend on the CPU memory manager at all.
|
||||||
KernelContext.Device.Gpu.SetVmm(CpuMemory);
|
if (flags.HasFlag(ProcessCreationFlags.IsApplication))
|
||||||
|
{
|
||||||
|
KernelContext.Device.Gpu.SetVmm((MemoryManager)CpuMemory);
|
||||||
|
}
|
||||||
|
|
||||||
MemoryManager = new KMemoryManager(KernelContext, CpuMemory);
|
MemoryManager = new KMemoryManager(KernelContext, CpuMemory);
|
||||||
}
|
}
|
||||||
|
@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
throw new UndefinedInstructionException(e.Address, e.OpCode);
|
throw new UndefinedInstructionException(e.Address, e.OpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Destroy()
|
protected override void Destroy() => Context.Dispose();
|
||||||
{
|
|
||||||
CpuMemory.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ using Ryujinx.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
|
@ -24,29 +25,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
IrqAccessMask = new byte[0x80];
|
IrqAccessMask = new byte[0x80];
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager)
|
public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||||
{
|
{
|
||||||
AllowedCpuCoresMask = 0xf;
|
AllowedCpuCoresMask = 0xf;
|
||||||
AllowedThreadPriosMask = -1;
|
AllowedThreadPriosMask = -1;
|
||||||
DebuggingFlags &= ~3;
|
DebuggingFlags &= ~3;
|
||||||
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
||||||
|
|
||||||
return Parse(caps, memoryManager);
|
return Parse(capabilities, memoryManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult InitializeForUser(int[] caps, KMemoryManager memoryManager)
|
public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||||
{
|
{
|
||||||
return Parse(caps, memoryManager);
|
return Parse(capabilities, memoryManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KernelResult Parse(int[] caps, KMemoryManager memoryManager)
|
private KernelResult Parse(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||||
{
|
{
|
||||||
int mask0 = 0;
|
int mask0 = 0;
|
||||||
int mask1 = 0;
|
int mask1 = 0;
|
||||||
|
|
||||||
for (int index = 0; index < caps.Length; index++)
|
for (int index = 0; index < capabilities.Length; index++)
|
||||||
{
|
{
|
||||||
int cap = caps[index];
|
int cap = capabilities[index];
|
||||||
|
|
||||||
if (((cap + 1) & ~cap) != 0x40)
|
if (((cap + 1) & ~cap) != 0x40)
|
||||||
{
|
{
|
||||||
|
@ -59,14 +60,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((uint)index + 1 >= caps.Length)
|
if ((uint)index + 1 >= capabilities.Length)
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidCombination;
|
return KernelResult.InvalidCombination;
|
||||||
}
|
}
|
||||||
|
|
||||||
int prevCap = cap;
|
int prevCap = cap;
|
||||||
|
|
||||||
cap = caps[++index];
|
cap = capabilities[++index];
|
||||||
|
|
||||||
if (((cap + 1) & ~cap) != 0x40)
|
if (((cap + 1) & ~cap) != 0x40)
|
||||||
{
|
{
|
||||||
|
@ -91,9 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
return KernelResult.InvalidAddress;
|
return KernelResult.InvalidAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPermission perm = (prevCap >> 31) != 0
|
KMemoryPermission perm = (prevCap >> 31) != 0
|
||||||
? MemoryPermission.Read
|
? KMemoryPermission.Read
|
||||||
: MemoryPermission.ReadAndWrite;
|
: KMemoryPermission.ReadAndWrite;
|
||||||
|
|
||||||
KernelResult result;
|
KernelResult result;
|
||||||
|
|
||||||
|
@ -216,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
long address = ((long)(uint)cap << 4) & 0xffffff000;
|
long address = ((long)(uint)cap << 4) & 0xffffff000;
|
||||||
|
|
||||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, KMemoryPermission.ReadAndWrite);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
25
Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
Normal file
25
Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
{
|
||||||
|
class ProcessContext : IProcessContext
|
||||||
|
{
|
||||||
|
public IVirtualMemoryManager AddressSpace { get; }
|
||||||
|
|
||||||
|
public ProcessContext(IVirtualMemoryManager asManager)
|
||||||
|
{
|
||||||
|
AddressSpace = asManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(ExecutionContext context, ulong codeAddress)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
Normal file
13
Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
{
|
||||||
|
class ProcessContextFactory : IProcessContextFactory
|
||||||
|
{
|
||||||
|
public IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler)
|
||||||
|
{
|
||||||
|
return new ProcessContext(new AddressSpaceManager(backingMemory, addressSpaceSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
Normal file
38
Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
{
|
||||||
|
enum ProcessCreationFlags
|
||||||
|
{
|
||||||
|
Is64Bit = 1 << 0,
|
||||||
|
|
||||||
|
AddressSpaceShift = 1,
|
||||||
|
AddressSpace32Bit = 0 << AddressSpaceShift,
|
||||||
|
AddressSpace64BitDeprecated = 1 << AddressSpaceShift,
|
||||||
|
AddressSpace32BitWithoutAlias = 2 << AddressSpaceShift,
|
||||||
|
AddressSpace64Bit = 3 << AddressSpaceShift,
|
||||||
|
AddressSpaceMask = 7 << AddressSpaceShift,
|
||||||
|
|
||||||
|
EnableDebug = 1 << 4,
|
||||||
|
EnableAslr = 1 << 5,
|
||||||
|
IsApplication = 1 << 6,
|
||||||
|
DeprecatedUseSecureMemory = 1 << 7,
|
||||||
|
|
||||||
|
PoolPartitionShift = 7,
|
||||||
|
PoolPartitionApplication = 0 << PoolPartitionShift,
|
||||||
|
PoolPartitionApplet = 1 << PoolPartitionShift,
|
||||||
|
PoolPartitionSystem = 2 << PoolPartitionShift,
|
||||||
|
PoolPartitionSystemNonSecure = 3 << PoolPartitionShift,
|
||||||
|
PoolPartitionMask = 0xf << PoolPartitionShift,
|
||||||
|
|
||||||
|
OptimizeMemoryAllocation = 1 << 11,
|
||||||
|
|
||||||
|
All =
|
||||||
|
Is64Bit |
|
||||||
|
AddressSpaceMask |
|
||||||
|
EnableDebug |
|
||||||
|
EnableAslr |
|
||||||
|
IsApplication |
|
||||||
|
DeprecatedUseSecureMemory |
|
||||||
|
PoolPartitionMask |
|
||||||
|
OptimizeMemoryAllocation
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,36 +2,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
struct ProcessCreationInfo
|
struct ProcessCreationInfo
|
||||||
{
|
{
|
||||||
public string Name { get; private set; }
|
public string Name { get; }
|
||||||
|
|
||||||
public int Version { get; private set; }
|
public int Version { get; }
|
||||||
public ulong TitleId { get; private set; }
|
public ulong TitleId { get; }
|
||||||
|
|
||||||
public ulong CodeAddress { get; private set; }
|
public ulong CodeAddress { get; }
|
||||||
public int CodePagesCount { get; private set; }
|
public int CodePagesCount { get; }
|
||||||
|
|
||||||
public int MmuFlags { get; private set; }
|
public ProcessCreationFlags Flags { get; }
|
||||||
public int ResourceLimitHandle { get; private set; }
|
public int ResourceLimitHandle { get; }
|
||||||
public int PersonalMmHeapPagesCount { get; private set; }
|
public int SystemResourcePagesCount { get; }
|
||||||
|
|
||||||
public ProcessCreationInfo(
|
public ProcessCreationInfo(
|
||||||
string name,
|
string name,
|
||||||
int category,
|
int version,
|
||||||
ulong titleId,
|
ulong titleId,
|
||||||
ulong codeAddress,
|
ulong codeAddress,
|
||||||
int codePagesCount,
|
int codePagesCount,
|
||||||
int mmuFlags,
|
ProcessCreationFlags flags,
|
||||||
int resourceLimitHandle,
|
int resourceLimitHandle,
|
||||||
int personalMmHeapPagesCount)
|
int systemResourcePagesCount)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Version = category;
|
Version = version;
|
||||||
TitleId = titleId;
|
TitleId = titleId;
|
||||||
CodeAddress = codeAddress;
|
CodeAddress = codeAddress;
|
||||||
CodePagesCount = codePagesCount;
|
CodePagesCount = codePagesCount;
|
||||||
MmuFlags = mmuFlags;
|
Flags = flags;
|
||||||
ResourceLimitHandle = resourceLimitHandle;
|
ResourceLimitHandle = resourceLimitHandle;
|
||||||
PersonalMmHeapPagesCount = personalMmHeapPagesCount;
|
SystemResourcePagesCount = systemResourcePagesCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,21 +7,167 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
{
|
{
|
||||||
class Syscall
|
class Syscall
|
||||||
{
|
{
|
||||||
private readonly Switch _device;
|
|
||||||
private readonly KernelContext _context;
|
private readonly KernelContext _context;
|
||||||
|
|
||||||
public Syscall(Switch device, KernelContext context)
|
public Syscall(KernelContext context)
|
||||||
{
|
{
|
||||||
_device = device;
|
|
||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process
|
||||||
|
|
||||||
|
public KernelResult GetProcessId(int handle, out long pid)
|
||||||
|
{
|
||||||
|
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||||
|
|
||||||
|
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
|
||||||
|
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
KThread thread = currentProcess.HandleTable.GetKThread(handle);
|
||||||
|
|
||||||
|
if (thread != null)
|
||||||
|
{
|
||||||
|
process = thread.Owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: KDebugEvent.
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = process?.Pid ?? 0;
|
||||||
|
|
||||||
|
return process != null
|
||||||
|
? KernelResult.Success
|
||||||
|
: KernelResult.InvalidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KernelResult CreateProcess(
|
||||||
|
ProcessCreationInfo info,
|
||||||
|
ReadOnlySpan<int> capabilities,
|
||||||
|
out int handle,
|
||||||
|
IProcessContextFactory contextFactory,
|
||||||
|
ThreadStart customThreadStart = null)
|
||||||
|
{
|
||||||
|
handle = 0;
|
||||||
|
|
||||||
|
if ((info.Flags & ~ProcessCreationFlags.All) != 0)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidEnumValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Address space check.
|
||||||
|
|
||||||
|
if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidEnumValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((info.CodeAddress & 0x1fffff) != 0)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
|
||||||
|
!info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable;
|
||||||
|
|
||||||
|
KProcess process = new KProcess(_context);
|
||||||
|
|
||||||
|
using var _ = new OnScopeExit(process.DecrementReferenceCount);
|
||||||
|
|
||||||
|
KResourceLimit resourceLimit;
|
||||||
|
|
||||||
|
if (info.ResourceLimitHandle != 0)
|
||||||
|
{
|
||||||
|
resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
|
||||||
|
|
||||||
|
if (resourceLimit == null)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resourceLimit = _context.ResourceLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch
|
||||||
|
{
|
||||||
|
ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application,
|
||||||
|
ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet,
|
||||||
|
ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service,
|
||||||
|
ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices,
|
||||||
|
_ => MemoryRegion.NvServices
|
||||||
|
};
|
||||||
|
|
||||||
|
KernelResult result = process.Initialize(
|
||||||
|
info,
|
||||||
|
capabilities,
|
||||||
|
resourceLimit,
|
||||||
|
memRegion,
|
||||||
|
contextFactory,
|
||||||
|
customThreadStart);
|
||||||
|
|
||||||
|
if (result != KernelResult.Success)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Processes.TryAdd(process.Pid, process);
|
||||||
|
|
||||||
|
return handleTable.GenerateHandle(process, out handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
|
||||||
|
{
|
||||||
|
KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
|
||||||
|
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidCpuCore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority))
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.DefaultCpuCore = cpuCore;
|
||||||
|
|
||||||
|
KernelResult result = process.Start(priority, mainThreadStackSize);
|
||||||
|
|
||||||
|
if (result != KernelResult.Success)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.IncrementReferenceCount();
|
||||||
|
|
||||||
|
return KernelResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
// IPC
|
// IPC
|
||||||
|
|
||||||
public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
|
public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
|
||||||
|
@ -33,6 +179,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.UserCopyFailed;
|
return KernelResult.UserCopyFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ConnectToNamedPort(name, out handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KernelResult ConnectToNamedPort(string name, out int handle)
|
||||||
|
{
|
||||||
|
handle = 0;
|
||||||
|
|
||||||
if (name.Length > 11)
|
if (name.Length > 11)
|
||||||
{
|
{
|
||||||
return KernelResult.MaximumExceeded;
|
return KernelResult.MaximumExceeded;
|
||||||
|
@ -70,61 +223,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SendSyncRequestHLE(int handle)
|
public KernelResult SendSyncRequest(int handle)
|
||||||
{
|
|
||||||
KProcess process = _context.Scheduler.GetCurrentProcess();
|
|
||||||
|
|
||||||
KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
|
|
||||||
|
|
||||||
if (clientSession == null || clientSession.Service == null)
|
|
||||||
{
|
|
||||||
return SendSyncRequest(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle)
|
|
||||||
{
|
|
||||||
KProcess process = _context.Scheduler.GetCurrentProcess();
|
|
||||||
|
|
||||||
byte[] messageData = new byte[messageSize];
|
|
||||||
|
|
||||||
process.CpuMemory.Read(messagePtr, messageData);
|
|
||||||
|
|
||||||
KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
|
|
||||||
|
|
||||||
if (clientSession == null || clientSession.Service == null)
|
|
||||||
{
|
|
||||||
return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientSession != null)
|
|
||||||
{
|
|
||||||
_context.CriticalSection.Enter();
|
|
||||||
|
|
||||||
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
|
||||||
|
|
||||||
currentThread.SignaledObj = null;
|
|
||||||
currentThread.ObjSyncResult = KernelResult.Success;
|
|
||||||
|
|
||||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
|
||||||
|
|
||||||
clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize);
|
|
||||||
|
|
||||||
_context.CriticalSection.Leave();
|
|
||||||
|
|
||||||
return currentThread.ObjSyncResult;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
|
|
||||||
|
|
||||||
return KernelResult.InvalidHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private KernelResult SendSyncRequest(int handle)
|
|
||||||
{
|
{
|
||||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||||
|
|
||||||
|
@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.UserCopyFailed;
|
return KernelResult.UserCopyFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
|
return ReplyAndReceive(handles, replyTargetHandle, timeout, out handleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < handlesCount; index++)
|
public KernelResult ReplyAndReceive(ReadOnlySpan<int> handles, int replyTargetHandle, long timeout, out int handleIndex)
|
||||||
|
{
|
||||||
|
handleIndex = 0;
|
||||||
|
|
||||||
|
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||||
|
|
||||||
|
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handles.Length];
|
||||||
|
|
||||||
|
for (int index = 0; index < handles.Length; index++)
|
||||||
{
|
{
|
||||||
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
|
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
|
||||||
|
|
||||||
|
@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.UserCopyFailed;
|
return KernelResult.UserCopyFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxSessions < 0 || name.Length > 11)
|
if (name.Length > 11)
|
||||||
|
{
|
||||||
|
return KernelResult.MaximumExceeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ManageNamedPort(name, maxSessions, out handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KernelResult ManageNamedPort(string name, int maxSessions, out int handle)
|
||||||
|
{
|
||||||
|
handle = 0;
|
||||||
|
|
||||||
|
if (maxSessions < 0)
|
||||||
{
|
{
|
||||||
return KernelResult.MaximumExceeded;
|
return KernelResult.MaximumExceeded;
|
||||||
}
|
}
|
||||||
|
@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
|
public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
if (!PageAligned(address))
|
if (!PageAligned(address))
|
||||||
{
|
{
|
||||||
|
@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidMemState;
|
return KernelResult.InvalidMemState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
|
if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidPermission;
|
return KernelResult.InvalidPermission;
|
||||||
}
|
}
|
||||||
|
@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
currentProcess);
|
currentProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
|
public KernelResult CreateTransferMemory(ulong address, ulong size, KMemoryPermission permission, out int handle)
|
||||||
{
|
{
|
||||||
handle = 0;
|
handle = 0;
|
||||||
|
|
||||||
|
@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidMemState;
|
return KernelResult.InvalidMemState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
|
if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidPermission;
|
return KernelResult.InvalidPermission;
|
||||||
}
|
}
|
||||||
|
@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
|
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
if (!PageAligned(src))
|
if (!PageAligned(src))
|
||||||
{
|
{
|
||||||
|
@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidSize;
|
return KernelResult.InvalidSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permission != MemoryPermission.None &&
|
if (permission != KMemoryPermission.None &&
|
||||||
permission != MemoryPermission.Read &&
|
permission != KMemoryPermission.Read &&
|
||||||
permission != MemoryPermission.ReadAndWrite &&
|
permission != KMemoryPermission.ReadAndWrite &&
|
||||||
permission != MemoryPermission.ReadAndExecute)
|
permission != KMemoryPermission.ReadAndExecute)
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidPermission;
|
return KernelResult.InvalidPermission;
|
||||||
}
|
}
|
||||||
|
@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return _context.Scheduler.GetCurrentThread().Context.CntpctEl0;
|
return _context.Scheduler.GetCurrentThread().Context.CntpctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult GetProcessId(int handle, out long pid)
|
|
||||||
{
|
|
||||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
|
||||||
|
|
||||||
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
|
|
||||||
|
|
||||||
if (process == null)
|
|
||||||
{
|
|
||||||
KThread thread = currentProcess.HandleTable.GetKThread(handle);
|
|
||||||
|
|
||||||
if (thread != null)
|
|
||||||
{
|
|
||||||
process = thread.Owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: KDebugEvent.
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = process?.Pid ?? 0;
|
|
||||||
|
|
||||||
return process != null
|
|
||||||
? KernelResult.Success
|
|
||||||
: KernelResult.InvalidHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Break(ulong reason)
|
public void Break(ulong reason)
|
||||||
{
|
{
|
||||||
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
||||||
|
@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return KernelResult.InvalidThread;
|
return KernelResult.InvalidThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryManager memory = currentProcess.CpuMemory;
|
IVirtualMemoryManager memory = currentProcess.CpuMemory;
|
||||||
|
|
||||||
memory.Write(address + 0x0, thread.Context.GetX(0));
|
memory.Write(address + 0x0, thread.Context.GetX(0));
|
||||||
memory.Write(address + 0x8, thread.Context.GetX(1));
|
memory.Write(address + 0x8, thread.Context.GetX(1));
|
||||||
|
|
|
@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
public KernelResult SendSyncRequest32([R(0)] int handle)
|
public KernelResult SendSyncRequest32([R(0)] int handle)
|
||||||
{
|
{
|
||||||
return _syscall.SendSyncRequestHLE(handle);
|
return _syscall.SendSyncRequest(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle)
|
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle)
|
||||||
{
|
{
|
||||||
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
|
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult CreateSession32(
|
public KernelResult CreateSession32(
|
||||||
|
@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission)
|
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
return _syscall.MapSharedMemory(handle, address, size, permission);
|
return _syscall.MapSharedMemory(handle, address, size, permission);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
public KernelResult CreateTransferMemory32(
|
public KernelResult CreateTransferMemory32(
|
||||||
[R(1)] uint address,
|
[R(1)] uint address,
|
||||||
[R(2)] uint size,
|
[R(2)] uint size,
|
||||||
[R(3)] MemoryPermission permission,
|
[R(3)] KMemoryPermission permission,
|
||||||
[R(1)] out int handle)
|
[R(1)] out int handle)
|
||||||
{
|
{
|
||||||
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
||||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
[R(2)] uint srcLow,
|
[R(2)] uint srcLow,
|
||||||
[R(3)] uint srcHigh,
|
[R(3)] uint srcHigh,
|
||||||
[R(4)] uint sizeHigh,
|
[R(4)] uint sizeHigh,
|
||||||
[R(5)] MemoryPermission permission)
|
[R(5)] KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong src = srcLow | ((ulong)srcHigh << 32);
|
ulong src = srcLow | ((ulong)srcHigh << 32);
|
||||||
ulong size = sizeLow | ((ulong)sizeHigh << 32);
|
ulong size = sizeLow | ((ulong)sizeHigh << 32);
|
||||||
|
|
|
@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
public KernelResult SendSyncRequest64([R(0)] int handle)
|
public KernelResult SendSyncRequest64([R(0)] int handle)
|
||||||
{
|
{
|
||||||
return _syscall.SendSyncRequestHLE(handle);
|
return _syscall.SendSyncRequest(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle)
|
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle)
|
||||||
{
|
{
|
||||||
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
|
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SendAsyncRequestWithUserBuffer64(
|
public KernelResult SendAsyncRequestWithUserBuffer64(
|
||||||
|
@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return _syscall.QueryMemory(infoPtr, position, out pageInfo);
|
return _syscall.QueryMemory(infoPtr, position, out pageInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission)
|
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
return _syscall.MapSharedMemory(handle, address, size, permission);
|
return _syscall.MapSharedMemory(handle, address, size, permission);
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
public KernelResult CreateTransferMemory64(
|
public KernelResult CreateTransferMemory64(
|
||||||
[R(1)] ulong address,
|
[R(1)] ulong address,
|
||||||
[R(2)] ulong size,
|
[R(2)] ulong size,
|
||||||
[R(3)] MemoryPermission permission,
|
[R(3)] KMemoryPermission permission,
|
||||||
[R(1)] out int handle)
|
[R(1)] out int handle)
|
||||||
{
|
{
|
||||||
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
||||||
|
@ -172,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
|
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
|
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
|
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,6 +229,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
|
||||||
KProcess dummyProcess = new KProcess(_context);
|
KProcess dummyProcess = new KProcess(_context);
|
||||||
|
|
||||||
|
dummyProcess.HandleTable.Initialize(1024);
|
||||||
|
|
||||||
KThread dummyThread = new KThread(_context);
|
KThread dummyThread = new KThread(_context);
|
||||||
|
|
||||||
dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy);
|
dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy);
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
public ulong CondVarAddress { get; set; }
|
public ulong CondVarAddress { get; set; }
|
||||||
|
|
||||||
private ulong _entrypoint;
|
private ulong _entrypoint;
|
||||||
|
private ThreadStart _customThreadStart;
|
||||||
|
|
||||||
public ulong MutexAddress { get; set; }
|
public ulong MutexAddress { get; set; }
|
||||||
|
|
||||||
|
@ -48,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
|
||||||
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
|
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
|
||||||
|
|
||||||
public LinkedList<KThread> Withholder { get; set; }
|
public LinkedList<KThread> Withholder { get; set; }
|
||||||
public LinkedListNode<KThread> WithholderNode { get; set; }
|
public LinkedListNode<KThread> WithholderNode { get; set; }
|
||||||
|
|
||||||
public LinkedListNode<KThread> ProcessListNode { get; set; }
|
public LinkedListNode<KThread> ProcessListNode { get; set; }
|
||||||
|
|
||||||
private LinkedList<KThread> _mutexWaiters;
|
private LinkedList<KThread> _mutexWaiters;
|
||||||
private LinkedListNode<KThread> _mutexWaiterNode;
|
private LinkedListNode<KThread> _mutexWaiterNode;
|
||||||
|
|
||||||
public KThread MutexOwner { get; private set; }
|
public KThread MutexOwner { get; private set; }
|
||||||
|
@ -65,24 +66,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
public KernelResult ObjSyncResult { get; set; }
|
public KernelResult ObjSyncResult { get; set; }
|
||||||
|
|
||||||
public int DynamicPriority { get; set; }
|
public int DynamicPriority { get; set; }
|
||||||
public int CurrentCore { get; set; }
|
public int CurrentCore { get; set; }
|
||||||
public int BasePriority { get; set; }
|
public int BasePriority { get; set; }
|
||||||
public int PreferredCore { get; set; }
|
public int PreferredCore { get; set; }
|
||||||
|
|
||||||
private long _affinityMaskOverride;
|
private long _affinityMaskOverride;
|
||||||
private int _preferredCoreOverride;
|
private int _preferredCoreOverride;
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649
|
||||||
private int _affinityOverrideCount;
|
private int _affinityOverrideCount;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
public ThreadSchedState SchedFlags { get; private set; }
|
public ThreadSchedState SchedFlags { get; private set; }
|
||||||
|
|
||||||
private int _shallBeTerminated;
|
private int _shallBeTerminated;
|
||||||
|
|
||||||
public bool ShallBeTerminated { get => _shallBeTerminated != 0; set => _shallBeTerminated = value ? 1 : 0; }
|
public bool ShallBeTerminated
|
||||||
|
{
|
||||||
|
get => _shallBeTerminated != 0;
|
||||||
|
set => _shallBeTerminated = value ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public bool SyncCancelled { get; set; }
|
public bool SyncCancelled { get; set; }
|
||||||
public bool WaitingSync { get; set; }
|
public bool WaitingSync { get; set; }
|
||||||
|
|
||||||
private bool _hasExited;
|
private bool _hasExited;
|
||||||
private bool _hasBeenInitialized;
|
private bool _hasBeenInitialized;
|
||||||
|
@ -98,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
|
||||||
public KThread(KernelContext context) : base(context)
|
public KThread(KernelContext context) : base(context)
|
||||||
{
|
{
|
||||||
_scheduler = KernelContext.Scheduler;
|
_scheduler = KernelContext.Scheduler;
|
||||||
_schedulingData = KernelContext.Scheduler.SchedulingData;
|
_schedulingData = KernelContext.Scheduler.SchedulingData;
|
||||||
|
|
||||||
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
|
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
|
||||||
|
@ -110,14 +115,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult Initialize(
|
public KernelResult Initialize(
|
||||||
ulong entrypoint,
|
ulong entrypoint,
|
||||||
ulong argsPtr,
|
ulong argsPtr,
|
||||||
ulong stackTop,
|
ulong stackTop,
|
||||||
int priority,
|
int priority,
|
||||||
int defaultCpuCore,
|
int defaultCpuCore,
|
||||||
KProcess owner,
|
KProcess owner,
|
||||||
ThreadType type = ThreadType.User,
|
ThreadType type,
|
||||||
ThreadStart customHostThreadStart = null)
|
ThreadStart customThreadStart = null)
|
||||||
{
|
{
|
||||||
if ((uint)type > 3)
|
if ((uint)type > 3)
|
||||||
{
|
{
|
||||||
|
@ -135,11 +140,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
CurrentCore = PreferredCore;
|
CurrentCore = PreferredCore;
|
||||||
|
|
||||||
DynamicPriority = priority;
|
DynamicPriority = priority;
|
||||||
BasePriority = priority;
|
BasePriority = priority;
|
||||||
|
|
||||||
ObjSyncResult = KernelResult.ThreadNotStarted;
|
ObjSyncResult = KernelResult.ThreadNotStarted;
|
||||||
|
|
||||||
_entrypoint = entrypoint;
|
_entrypoint = entrypoint;
|
||||||
|
_customThreadStart = customThreadStart;
|
||||||
|
|
||||||
if (type == ThreadType.User)
|
if (type == ThreadType.User)
|
||||||
{
|
{
|
||||||
|
@ -162,18 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
owner.IncrementReferenceCount();
|
owner.IncrementReferenceCount();
|
||||||
owner.IncrementThreadCount();
|
owner.IncrementThreadCount();
|
||||||
|
|
||||||
is64Bits = (owner.MmuFlags & 1) != 0;
|
is64Bits = owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is64Bits = true;
|
is64Bits = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint)));
|
HostThread = new Thread(ThreadStart);
|
||||||
|
|
||||||
Context = CpuContext.CreateExecutionContext();
|
Context = CpuContext.CreateExecutionContext();
|
||||||
|
|
||||||
bool isAarch32 = (Owner.MmuFlags & 1) == 0;
|
bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||||
|
|
||||||
Context.IsAarch32 = isAarch32;
|
Context.IsAarch32 = isAarch32;
|
||||||
|
|
||||||
|
@ -189,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.CntfrqEl0 = 19200000;
|
Context.CntfrqEl0 = 19200000;
|
||||||
Context.Tpidr = (long)_tlsAddress;
|
Context.Tpidr = (long)_tlsAddress;
|
||||||
|
|
||||||
owner.SubscribeThreadEventHandlers(Context);
|
owner.SubscribeThreadEventHandlers(Context);
|
||||||
|
|
||||||
|
@ -249,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
{
|
{
|
||||||
KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
|
KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
|
||||||
|
|
||||||
while (SchedFlags != ThreadSchedState.TerminationPending &&
|
while (SchedFlags != ThreadSchedState.TerminationPending &&
|
||||||
currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
|
currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
|
||||||
!currentThread.ShallBeTerminated)
|
!currentThread.ShallBeTerminated)
|
||||||
{
|
{
|
||||||
|
@ -351,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
Context.RequestInterrupt();
|
Context.RequestInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
SignaledObj = null;
|
SignaledObj = null;
|
||||||
ObjSyncResult = KernelResult.ThreadTerminating;
|
ObjSyncResult = KernelResult.ThreadTerminating;
|
||||||
|
|
||||||
ReleaseAndResume();
|
ReleaseAndResume();
|
||||||
|
@ -524,7 +530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
// If the candidate was scheduled after the current thread, then it's not worth it,
|
// If the candidate was scheduled after the current thread, then it's not worth it,
|
||||||
// unless the priority is higher than the current one.
|
// unless the priority is higher than the current one.
|
||||||
if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
|
if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
|
||||||
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
|
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
|
||||||
{
|
{
|
||||||
yield return thread;
|
yield return thread;
|
||||||
}
|
}
|
||||||
|
@ -701,7 +707,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SignaledObj = null;
|
SignaledObj = null;
|
||||||
ObjSyncResult = KernelResult.Cancelled;
|
ObjSyncResult = KernelResult.Cancelled;
|
||||||
|
|
||||||
SetNewSchedFlags(ThreadSchedState.Running);
|
SetNewSchedFlags(ThreadSchedState.Running);
|
||||||
|
@ -734,14 +740,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
if (useOverride)
|
if (useOverride)
|
||||||
{
|
{
|
||||||
_preferredCoreOverride = newCore;
|
_preferredCoreOverride = newCore;
|
||||||
_affinityMaskOverride = newAffinityMask;
|
_affinityMaskOverride = newAffinityMask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long oldAffinityMask = AffinityMask;
|
long oldAffinityMask = AffinityMask;
|
||||||
|
|
||||||
PreferredCore = newCore;
|
PreferredCore = newCore;
|
||||||
AffinityMask = newAffinityMask;
|
AffinityMask = newAffinityMask;
|
||||||
|
|
||||||
if (oldAffinityMask != newAffinityMask)
|
if (oldAffinityMask != newAffinityMask)
|
||||||
{
|
{
|
||||||
|
@ -783,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
|
||||||
private void CombineForcePauseFlags()
|
private void CombineForcePauseFlags()
|
||||||
{
|
{
|
||||||
ThreadSchedState oldFlags = SchedFlags;
|
ThreadSchedState oldFlags = SchedFlags;
|
||||||
ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
|
ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
|
||||||
|
|
||||||
SchedFlags = lowNibble | _forcePauseFlags;
|
SchedFlags = lowNibble | _forcePauseFlags;
|
||||||
|
@ -1143,19 +1149,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThreadStart(ulong entrypoint)
|
private void ThreadStart()
|
||||||
{
|
{
|
||||||
Owner.CpuContext.Execute(Context, entrypoint);
|
KernelStatic.SetKernelContext(KernelContext);
|
||||||
|
|
||||||
ThreadExit();
|
if (_customThreadStart != null)
|
||||||
|
{
|
||||||
|
_customThreadStart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Owner.Context.Execute(Context, _entrypoint);
|
||||||
|
}
|
||||||
|
|
||||||
Context.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThreadExit()
|
|
||||||
{
|
|
||||||
KernelContext.Scheduler.ExitThread(this);
|
KernelContext.Scheduler.ExitThread(this);
|
||||||
KernelContext.Scheduler.RemoveThread(this);
|
KernelContext.Scheduler.RemoveThread(this);
|
||||||
|
|
||||||
|
Context.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCurrentHostThread()
|
public bool IsCurrentHostThread()
|
||||||
|
@ -1203,9 +1213,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
// Wake up all threads that may be waiting for a mutex being held by this thread.
|
// Wake up all threads that may be waiting for a mutex being held by this thread.
|
||||||
foreach (KThread thread in _mutexWaiters)
|
foreach (KThread thread in _mutexWaiters)
|
||||||
{
|
{
|
||||||
thread.MutexOwner = null;
|
thread.MutexOwner = null;
|
||||||
thread._preferredCoreOverride = 0;
|
thread._preferredCoreOverride = 0;
|
||||||
thread.ObjSyncResult = KernelResult.InvalidState;
|
thread.ObjSyncResult = KernelResult.InvalidState;
|
||||||
|
|
||||||
thread.ReleaseAndResume();
|
thread.ReleaseAndResume();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,23 +36,23 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;
|
ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;
|
||||||
|
|
||||||
int mmuFlags = 0;
|
ProcessCreationFlags flags = 0;
|
||||||
|
|
||||||
if (AslrEnabled)
|
if (AslrEnabled)
|
||||||
{
|
{
|
||||||
// TODO: Randomization.
|
// TODO: Randomization.
|
||||||
|
|
||||||
mmuFlags |= 0x20;
|
flags |= ProcessCreationFlags.EnableAslr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kip.Is64BitAddressSpace)
|
if (kip.Is64BitAddressSpace)
|
||||||
{
|
{
|
||||||
mmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
|
flags |= ProcessCreationFlags.AddressSpace64Bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kip.Is64Bit)
|
if (kip.Is64Bit)
|
||||||
{
|
{
|
||||||
mmuFlags |= 1;
|
flags |= ProcessCreationFlags.Is64Bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessCreationInfo creationInfo = new ProcessCreationInfo(
|
ProcessCreationInfo creationInfo = new ProcessCreationInfo(
|
||||||
|
@ -61,7 +61,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
kip.ProgramId,
|
kip.ProgramId,
|
||||||
codeAddress,
|
codeAddress,
|
||||||
codePagesCount,
|
codePagesCount,
|
||||||
mmuFlags,
|
flags,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
|
@ -82,12 +82,15 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
KProcess process = new KProcess(context);
|
KProcess process = new KProcess(context);
|
||||||
|
|
||||||
|
var processContextFactory = new ArmProcessContextFactory();
|
||||||
|
|
||||||
result = process.InitializeKip(
|
result = process.InitializeKip(
|
||||||
creationInfo,
|
creationInfo,
|
||||||
kip.Capabilities,
|
kip.Capabilities,
|
||||||
pageList,
|
pageList,
|
||||||
context.ResourceLimit,
|
context.ResourceLimit,
|
||||||
memoryRegion);
|
memoryRegion,
|
||||||
|
processContextFactory);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +186,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
metaData.Aci0.TitleId,
|
metaData.Aci0.TitleId,
|
||||||
codeStart,
|
codeStart,
|
||||||
codePagesCount,
|
codePagesCount,
|
||||||
metaData.MmuFlags,
|
(ProcessCreationFlags)metaData.ProcessFlags | ProcessCreationFlags.IsApplication,
|
||||||
0,
|
0,
|
||||||
personalMmHeapPagesCount);
|
personalMmHeapPagesCount);
|
||||||
|
|
||||||
|
@ -217,11 +220,14 @@ namespace Ryujinx.HLE.HOS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var processContextFactory = new ArmProcessContextFactory();
|
||||||
|
|
||||||
result = process.Initialize(
|
result = process.Initialize(
|
||||||
creationInfo,
|
creationInfo,
|
||||||
metaData.Aci0.KernelAccessControl.Capabilities,
|
metaData.Aci0.KernelAccessControl.Capabilities,
|
||||||
resourceLimit,
|
resourceLimit,
|
||||||
memoryRegion);
|
memoryRegion,
|
||||||
|
processContextFactory);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -280,7 +286,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
MemoryHelper.FillWithZeros(process.CpuMemory, (long)bssStart, image.BssSize);
|
MemoryHelper.FillWithZeros(process.CpuMemory, (long)bssStart, image.BssSize);
|
||||||
|
|
||||||
KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission)
|
KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
|
@ -292,21 +298,21 @@ namespace Ryujinx.HLE.HOS
|
||||||
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
|
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, MemoryPermission.ReadAndExecute);
|
KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, MemoryPermission.Read);
|
result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SetProcessMemoryPermission(dataStart, end - dataStart, MemoryPermission.ReadAndWrite);
|
return SetProcessMemoryPermission(dataStart, end - dataStart, KMemoryPermission.ReadAndWrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,43 +1,39 @@
|
||||||
using Ryujinx.Cpu;
|
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS
|
namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
class ServiceCtx
|
class ServiceCtx
|
||||||
{
|
{
|
||||||
public Switch Device { get; }
|
public Switch Device { get; }
|
||||||
public KProcess Process { get; }
|
public KProcess Process { get; }
|
||||||
public MemoryManager Memory { get; }
|
public IVirtualMemoryManager Memory { get; }
|
||||||
public KThread Thread { get; }
|
public KThread Thread { get; }
|
||||||
public KClientSession Session { get; }
|
public IpcMessage Request { get; }
|
||||||
public IpcMessage Request { get; }
|
public IpcMessage Response { get; }
|
||||||
public IpcMessage Response { get; }
|
public BinaryReader RequestData { get; }
|
||||||
public BinaryReader RequestData { get; }
|
public BinaryWriter ResponseData { get; }
|
||||||
public BinaryWriter ResponseData { get; }
|
|
||||||
|
|
||||||
public ServiceCtx(
|
public ServiceCtx(
|
||||||
Switch device,
|
Switch device,
|
||||||
KProcess process,
|
KProcess process,
|
||||||
MemoryManager memory,
|
IVirtualMemoryManager memory,
|
||||||
KThread thread,
|
KThread thread,
|
||||||
KClientSession session,
|
IpcMessage request,
|
||||||
IpcMessage request,
|
IpcMessage response,
|
||||||
IpcMessage response,
|
BinaryReader requestData,
|
||||||
BinaryReader requestData,
|
BinaryWriter responseData)
|
||||||
BinaryWriter responseData)
|
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
Process = process;
|
Process = process;
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
Thread = thread;
|
Thread = thread;
|
||||||
Session = session;
|
Request = request;
|
||||||
Request = request;
|
Response = response;
|
||||||
Response = response;
|
RequestData = requestData;
|
||||||
RequestData = requestData;
|
|
||||||
ResponseData = responseData;
|
ResponseData = responseData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
||||||
{
|
{
|
||||||
class ISystemAppletProxy : IpcService
|
class ISystemAppletProxy : IpcService
|
||||||
{
|
{
|
||||||
public ISystemAppletProxy() { }
|
private readonly long _pid;
|
||||||
|
|
||||||
|
public ISystemAppletProxy(long pid)
|
||||||
|
{
|
||||||
|
_pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
||||||
|
@ -19,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
||||||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||||
public ResultCode GetSelfController(ServiceCtx context)
|
public ResultCode GetSelfController(ServiceCtx context)
|
||||||
{
|
{
|
||||||
MakeObject(context, new ISelfController(context.Device.System));
|
MakeObject(context, new ISelfController(context.Device.System, _pid));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
||||||
// GetWindowController() -> object<nn::am::service::IWindowController>
|
// GetWindowController() -> object<nn::am::service::IWindowController>
|
||||||
public ResultCode GetWindowController(ServiceCtx context)
|
public ResultCode GetWindowController(ServiceCtx context)
|
||||||
{
|
{
|
||||||
MakeObject(context, new IWindowController());
|
MakeObject(context, new IWindowController(_pid));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||||
private KEvent _normalOutDataEvent;
|
private KEvent _normalOutDataEvent;
|
||||||
private KEvent _interactiveOutDataEvent;
|
private KEvent _interactiveOutDataEvent;
|
||||||
|
|
||||||
|
private int _stateChangedEventHandle;
|
||||||
|
private int _normalOutDataEventHandle;
|
||||||
|
private int _interactiveOutDataEventHandle;
|
||||||
|
|
||||||
public ILibraryAppletAccessor(AppletId appletId, Horizon system)
|
public ILibraryAppletAccessor(AppletId appletId, Horizon system)
|
||||||
{
|
{
|
||||||
_stateChangedEvent = new KEvent(system.KernelContext);
|
_stateChangedEvent = new KEvent(system.KernelContext);
|
||||||
|
@ -55,12 +59,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||||
// GetAppletStateChangedEvent() -> handle<copy>
|
// GetAppletStateChangedEvent() -> handle<copy>
|
||||||
public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -69,8 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||||
// Start()
|
// Start()
|
||||||
public ResultCode Start(ServiceCtx context)
|
public ResultCode Start(ServiceCtx context)
|
||||||
{
|
{
|
||||||
return (ResultCode)_applet.Start(_normalSession.GetConsumer(),
|
return (ResultCode)_applet.Start(_normalSession.GetConsumer(), _interactiveSession.GetConsumer());
|
||||||
_interactiveSession.GetConsumer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(30)]
|
[Command(30)]
|
||||||
|
@ -138,12 +144,16 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||||
// GetPopOutDataEvent() -> handle<copy>
|
// GetPopOutDataEvent() -> handle<copy>
|
||||||
public ResultCode GetPopOutDataEvent(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -152,12 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||||
// GetPopInteractiveOutDataEvent() -> handle<copy>
|
// GetPopInteractiveOutDataEvent() -> handle<copy>
|
||||||
public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
private Apm.SystemManagerServer _apmSystemManagerServer;
|
private Apm.SystemManagerServer _apmSystemManagerServer;
|
||||||
private Lbl.LblControllerServer _lblControllerServer;
|
private Lbl.LblControllerServer _lblControllerServer;
|
||||||
|
|
||||||
private bool _vrModeEnabled = false;
|
private bool _vrModeEnabled;
|
||||||
|
private int _messageEventHandle;
|
||||||
|
private int _displayResolutionChangedEventHandle;
|
||||||
|
|
||||||
public ICommonStateGetter(ServiceCtx context)
|
public ICommonStateGetter(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
@ -25,14 +27,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
// GetEventHandle() -> handle<copy>
|
// GetEventHandle() -> handle<copy>
|
||||||
public ResultCode GetEventHandle(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -164,12 +169,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
// GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
|
// GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
|
||||||
public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
|
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);
|
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
class IHomeMenuFunctions : IpcService
|
class IHomeMenuFunctions : IpcService
|
||||||
{
|
{
|
||||||
private KEvent _channelEvent;
|
private KEvent _channelEvent;
|
||||||
|
private int _channelEventHandle;
|
||||||
|
|
||||||
public IHomeMenuFunctions(Horizon system)
|
public IHomeMenuFunctions(Horizon system)
|
||||||
{
|
{
|
||||||
|
@ -29,12 +30,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
// GetPopFromGeneralChannelEvent() -> handle<copy>
|
// GetPopFromGeneralChannelEvent() -> handle<copy>
|
||||||
public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context)
|
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);
|
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = new byte[transferMem.Size];
|
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));
|
MakeObject(context, new IStorage(data));
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
{
|
{
|
||||||
class ISelfController : IpcService
|
class ISelfController : IpcService
|
||||||
{
|
{
|
||||||
|
private readonly long _pid;
|
||||||
|
|
||||||
private KEvent _libraryAppletLaunchableEvent;
|
private KEvent _libraryAppletLaunchableEvent;
|
||||||
|
private int _libraryAppletLaunchableEventHandle;
|
||||||
|
|
||||||
private KEvent _accumulatedSuspendedTickChangedEvent;
|
private KEvent _accumulatedSuspendedTickChangedEvent;
|
||||||
private int _accumulatedSuspendedTickChangedEventHandle = 0;
|
private int _accumulatedSuspendedTickChangedEventHandle;
|
||||||
|
|
||||||
private object _fatalSectionLock = new object();
|
private object _fatalSectionLock = new object();
|
||||||
private int _fatalSectionCount;
|
private int _fatalSectionCount;
|
||||||
|
@ -32,9 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
private uint _screenShotImageOrientation = 0;
|
private uint _screenShotImageOrientation = 0;
|
||||||
private uint _idleTimeDetectionExtension = 0;
|
private uint _idleTimeDetectionExtension = 0;
|
||||||
|
|
||||||
public ISelfController(Horizon system)
|
public ISelfController(Horizon system, long pid)
|
||||||
{
|
{
|
||||||
_libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
|
_libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
|
||||||
|
_pid = pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
|
@ -103,12 +107,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
{
|
{
|
||||||
_libraryAppletLaunchableEvent.ReadableEvent.Signal();
|
_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);
|
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||||
|
|
||||||
|
@ -206,6 +213,31 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
return ResultCode.Success;
|
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)]
|
[Command(50)]
|
||||||
// SetHandlesRequestToDisplay(b8)
|
// SetHandlesRequestToDisplay(b8)
|
||||||
public ResultCode SetHandlesRequestToDisplay(ServiceCtx context)
|
public ResultCode SetHandlesRequestToDisplay(ServiceCtx context)
|
||||||
|
|
|
@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
{
|
{
|
||||||
class IWindowController : IpcService
|
class IWindowController : IpcService
|
||||||
{
|
{
|
||||||
public IWindowController() { }
|
private readonly long _pid;
|
||||||
|
|
||||||
|
public IWindowController(long pid)
|
||||||
|
{
|
||||||
|
_pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(1)]
|
[Command(1)]
|
||||||
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
|
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
|
||||||
|
@ -12,7 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||||
{
|
{
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
||||||
// OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
|
// OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
|
||||||
public ResultCode OpenSystemAppletProxy(ServiceCtx context)
|
public ResultCode OpenSystemAppletProxy(ServiceCtx context)
|
||||||
{
|
{
|
||||||
MakeObject(context, new ISystemAppletProxy());
|
MakeObject(context, new ISystemAppletProxy(context.Request.HandleDesc.PId));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
private KEvent _friendInvitationStorageChannelEvent;
|
private KEvent _friendInvitationStorageChannelEvent;
|
||||||
private KEvent _notificationStorageChannelEvent;
|
private KEvent _notificationStorageChannelEvent;
|
||||||
|
|
||||||
|
private int _gpuErrorDetectedSystemEventHandle;
|
||||||
|
private int _friendInvitationStorageChannelEventHandle;
|
||||||
|
private int _notificationStorageChannelEventHandle;
|
||||||
|
|
||||||
public IApplicationFunctions(Horizon system)
|
public IApplicationFunctions(Horizon system)
|
||||||
{
|
{
|
||||||
_gpuErrorDetectedSystemEvent = new KEvent(system.KernelContext);
|
_gpuErrorDetectedSystemEvent = new KEvent(system.KernelContext);
|
||||||
|
@ -293,12 +297,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height);
|
resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (transferMemoryHandle != 0)
|
||||||
if (transferMemoryHandle)
|
|
||||||
{
|
{
|
||||||
svcCloseHandle(transferMemoryHandle);
|
context.Device.System.KernelContext.Syscall.CloseHandle(transferMemoryHandle);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
|
@ -455,12 +457,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
// GetGpuErrorDetectedSystemEvent() -> handle<copy>
|
// GetGpuErrorDetectedSystemEvent() -> handle<copy>
|
||||||
public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context)
|
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.
|
// NOTE: This is used by "sdk" NSO during applet-application initialization.
|
||||||
// A seperate thread is setup where event-waiting is handled.
|
// A seperate thread is setup where event-waiting is handled.
|
||||||
|
@ -473,12 +478,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
// GetFriendInvitationStorageChannelEvent() -> handle<copy>
|
// GetFriendInvitationStorageChannelEvent() -> handle<copy>
|
||||||
public ResultCode GetFriendInvitationStorageChannelEvent(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -501,12 +509,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
// GetNotificationStorageChannelEvent() -> handle<copy>
|
// GetNotificationStorageChannelEvent() -> handle<copy>
|
||||||
public ResultCode GetNotificationStorageChannelEvent(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
||||||
{
|
{
|
||||||
class IApplicationProxy : IpcService
|
class IApplicationProxy : IpcService
|
||||||
{
|
{
|
||||||
public IApplicationProxy() { }
|
private readonly long _pid;
|
||||||
|
|
||||||
|
public IApplicationProxy(long pid)
|
||||||
|
{
|
||||||
|
_pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
||||||
|
@ -20,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
||||||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||||
public ResultCode GetSelfController(ServiceCtx context)
|
public ResultCode GetSelfController(ServiceCtx context)
|
||||||
{
|
{
|
||||||
MakeObject(context, new ISelfController(context.Device.System));
|
MakeObject(context, new ISelfController(context.Device.System, _pid));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
||||||
// GetWindowController() -> object<nn::am::service::IWindowController>
|
// GetWindowController() -> object<nn::am::service::IWindowController>
|
||||||
public ResultCode GetWindowController(ServiceCtx context)
|
public ResultCode GetWindowController(ServiceCtx context)
|
||||||
{
|
{
|
||||||
MakeObject(context, new IWindowController());
|
MakeObject(context, new IWindowController(_pid));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
||||||
// OpenApplicationProxy(u64, pid, handle<copy>) -> object<nn::am::service::IApplicationProxy>
|
// OpenApplicationProxy(u64, pid, handle<copy>) -> object<nn::am::service::IApplicationProxy>
|
||||||
public ResultCode OpenApplicationProxy(ServiceCtx context)
|
public ResultCode OpenApplicationProxy(ServiceCtx context)
|
||||||
{
|
{
|
||||||
MakeObject(context, new IApplicationProxy());
|
MakeObject(context, new IApplicationProxy(context.Request.HandleDesc.PId));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,18 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
|
||||||
{
|
{
|
||||||
class IAudioOut : IpcService, IDisposable
|
class IAudioOut : IpcService, IDisposable
|
||||||
{
|
{
|
||||||
private IAalOutput _audioOut;
|
private readonly IAalOutput _audioOut;
|
||||||
private KEvent _releaseEvent;
|
private readonly KEvent _releaseEvent;
|
||||||
private int _track;
|
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;
|
_audioOut = audioOut;
|
||||||
_releaseEvent = releaseEvent;
|
_releaseEvent = releaseEvent;
|
||||||
_track = track;
|
_track = track;
|
||||||
|
_clientHandle = clientHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
|
@ -59,12 +62,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
|
||||||
// RegisterBufferEvent() -> handle<copy>
|
// RegisterBufferEvent() -> handle<copy>
|
||||||
public ResultCode RegisterBufferEvent(ServiceCtx context)
|
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;
|
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.
|
// NOTE: Assume PCM16 all the time, change if new format are found.
|
||||||
short[] buffer = new short[data.SampleBufferSize / sizeof(short)];
|
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);
|
_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)
|
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)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,9 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
||||||
|
|
||||||
private IAudioRendererManager _impl;
|
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;
|
_impl = impl;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
||||||
MakeObject(context, new AudioRendererServer(renderer));
|
MakeObject(context, new AudioRendererServer(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.Device.System.KernelContext.Syscall.CloseHandle((int)processHandle);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
||||||
return ResultCode.Success;
|
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;
|
uint count = 0;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
||||||
private const int DefaultSampleRate = 48000;
|
private const int DefaultSampleRate = 48000;
|
||||||
private const int DefaultChannelsCount = 2;
|
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)]
|
[Command(0)]
|
||||||
// ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
|
// ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
|
||||||
|
@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
||||||
|
|
||||||
int track = audioOut.OpenTrack(sampleRate, channels, callback);
|
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(sampleRate);
|
||||||
context.ResponseData.Write(channels);
|
context.ResponseData.Write(channels);
|
||||||
|
|
|
@ -16,6 +16,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
||||||
|
|
||||||
MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount));
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
||||||
class IDeliveryCacheProgressService : IpcService
|
class IDeliveryCacheProgressService : IpcService
|
||||||
{
|
{
|
||||||
private KEvent _event;
|
private KEvent _event;
|
||||||
|
private int _eventHandle;
|
||||||
|
|
||||||
public IDeliveryCacheProgressService(ServiceCtx context)
|
public IDeliveryCacheProgressService(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
@ -22,12 +23,15 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
||||||
// GetEvent() -> handle<copy>
|
// GetEvent() -> handle<copy>
|
||||||
public ResultCode GetEvent(ServiceCtx context)
|
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);
|
Logger.Stub?.PrintStub(LogClass.ServiceBcat);
|
||||||
|
|
||||||
|
|
|
@ -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
|
// Workaround that by setting the application ID and owner ID if they're not already set
|
||||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
if (attribute.ProgramId == ProgramId.InvalidId)
|
||||||
{
|
{
|
||||||
attribute.ProgramId = new ProgramId(context.Process.TitleId);
|
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
|
||||||
}
|
|
||||||
|
|
||||||
if (creationInfo.OwnerId == 0)
|
|
||||||
{
|
|
||||||
creationInfo.OwnerId = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}");
|
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
|
// Workaround that by setting the application ID and owner ID if they're not already set
|
||||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
if (attribute.ProgramId == ProgramId.InvalidId)
|
||||||
{
|
{
|
||||||
attribute.ProgramId = new ProgramId(context.Process.TitleId);
|
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
|
||||||
}
|
|
||||||
|
|
||||||
if (creationInfo.OwnerId == 0)
|
|
||||||
{
|
|
||||||
creationInfo.OwnerId = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt);
|
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
|
// Workaround that by setting the application ID if it's not already set
|
||||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
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);
|
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
|
// Workaround that by setting the application ID if it's not already set
|
||||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
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);
|
Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
||||||
class IAppletResource : IpcService
|
class IAppletResource : IpcService
|
||||||
{
|
{
|
||||||
private KSharedMemory _hidSharedMem;
|
private KSharedMemory _hidSharedMem;
|
||||||
|
private int _hidSharedMemHandle;
|
||||||
|
|
||||||
public IAppletResource(KSharedMemory hidSharedMem)
|
public IAppletResource(KSharedMemory hidSharedMem)
|
||||||
{
|
{
|
||||||
|
@ -18,12 +19,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
||||||
// GetSharedMemoryHandle() -> handle<copy>
|
// GetSharedMemoryHandle() -> handle<copy>
|
||||||
public ResultCode GetSharedMemoryHandle(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
private HidAccelerometerParameters _accelerometerParams;
|
private HidAccelerometerParameters _accelerometerParams;
|
||||||
private HidVibrationValue _vibrationValue;
|
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);
|
_xpadIdEvent = new KEvent(context.Device.System.KernelContext);
|
||||||
_palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);
|
_palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
|
||||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -17,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
|
|
||||||
public ServerBase Server { get; private set; }
|
public ServerBase Server { get; private set; }
|
||||||
|
|
||||||
|
private IpcService _parent;
|
||||||
private IdDictionary _domainObjects;
|
private IdDictionary _domainObjects;
|
||||||
private int _selfId;
|
private int _selfId;
|
||||||
private bool _isDomain;
|
private bool _isDomain;
|
||||||
|
@ -32,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
|
|
||||||
Server = server;
|
Server = server;
|
||||||
|
|
||||||
|
_parent = this;
|
||||||
_domainObjects = new IdDictionary();
|
_domainObjects = new IdDictionary();
|
||||||
_selfId = -1;
|
_selfId = -1;
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
int domainWord0 = context.RequestData.ReadInt32();
|
int domainWord0 = context.RequestData.ReadInt32();
|
||||||
int domainObjId = context.RequestData.ReadInt32();
|
int domainObjId = context.RequestData.ReadInt32();
|
||||||
|
|
||||||
int domainCmd = (domainWord0 >> 0) & 0xff;
|
int domainCmd = (domainWord0 >> 0) & 0xff;
|
||||||
int inputObjCount = (domainWord0 >> 8) & 0xff;
|
int inputObjCount = (domainWord0 >> 8) & 0xff;
|
||||||
int dataPayloadSize = (domainWord0 >> 16) & 0xffff;
|
int dataPayloadSize = (domainWord0 >> 16) & 0xffff;
|
||||||
|
|
||||||
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
||||||
|
@ -96,8 +96,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long sfciMagic = context.RequestData.ReadInt64();
|
long sfciMagic = context.RequestData.ReadInt64();
|
||||||
int commandId = (int)context.RequestData.ReadInt64();
|
int commandId = (int)context.RequestData.ReadInt64();
|
||||||
|
|
||||||
bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest);
|
bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest);
|
||||||
|
|
||||||
|
@ -145,56 +145,37 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
{
|
{
|
||||||
string dbgMessage = $"{service.GetType().FullName}: {commandId}";
|
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 (_parent._isDomain)
|
||||||
|
|
||||||
if (service._isDomain)
|
|
||||||
{
|
{
|
||||||
context.Response.ObjectIds.Add(service.Add(obj));
|
obj._parent = _parent;
|
||||||
|
|
||||||
|
context.Response.ObjectIds.Add(_parent.Add(obj));
|
||||||
}
|
}
|
||||||
else
|
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)
|
context.Response.HandleDesc = IpcHandleDesc.MakeMove(clientSessionHandle);
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Out of handles!");
|
|
||||||
}
|
|
||||||
|
|
||||||
session.ServerSession.DecrementReferenceCount();
|
|
||||||
session.ClientSession.DecrementReferenceCount();
|
|
||||||
|
|
||||||
context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
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)
|
public bool TrySetServer(ServerBase newServer)
|
||||||
|
@ -230,5 +211,10 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
{
|
{
|
||||||
return _domainObjects.GetData<IIpcService>(id);
|
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>)
|
// StartDetection(bytes<8, 4>)
|
||||||
public ResultCode StartDetection(ServiceCtx context)
|
public ResultCode StartDetection(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(4)]
|
[Command(4)]
|
||||||
// StopDetection(bytes<8, 4>)
|
// StopDetection(bytes<8, 4>)
|
||||||
public ResultCode StopDetection(ServiceCtx context)
|
public ResultCode StopDetection(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(5)]
|
[Command(5)]
|
||||||
// Mount(bytes<8, 4>, u32, u32)
|
// Mount(bytes<8, 4>, u32, u32)
|
||||||
public ResultCode Mount(ServiceCtx context)
|
public ResultCode Mount(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(6)]
|
[Command(6)]
|
||||||
// Unmount(bytes<8, 4>)
|
// Unmount(bytes<8, 4>)
|
||||||
public ResultCode Unmount(ServiceCtx context)
|
public ResultCode Unmount(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(7)]
|
[Command(7)]
|
||||||
// OpenApplicationArea(bytes<8, 4>, u32)
|
// OpenApplicationArea(bytes<8, 4>, u32)
|
||||||
public ResultCode OpenApplicationArea(ServiceCtx context)
|
public ResultCode OpenApplicationArea(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(8)]
|
[Command(8)]
|
||||||
// GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
|
// GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
|
||||||
public ResultCode GetApplicationArea(ServiceCtx context)
|
public ResultCode GetApplicationArea(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(9)]
|
[Command(9)]
|
||||||
// SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
|
// SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
|
||||||
public ResultCode SetApplicationArea(ServiceCtx context)
|
public ResultCode SetApplicationArea(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(10)]
|
[Command(10)]
|
||||||
// Flush(bytes<8, 4>)
|
// Flush(bytes<8, 4>)
|
||||||
public ResultCode Flush(ServiceCtx context)
|
public ResultCode Flush(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(11)]
|
[Command(11)]
|
||||||
// Restore(bytes<8, 4>)
|
// Restore(bytes<8, 4>)
|
||||||
public ResultCode Restore(ServiceCtx context)
|
public ResultCode Restore(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(12)]
|
[Command(12)]
|
||||||
// CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
|
// CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
|
||||||
public ResultCode CreateApplicationArea(ServiceCtx context)
|
public ResultCode CreateApplicationArea(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(13)]
|
[Command(13)]
|
||||||
// GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
|
// GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
|
||||||
public ResultCode GetTagInfo(ServiceCtx context)
|
public ResultCode GetTagInfo(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(14)]
|
[Command(14)]
|
||||||
// GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
|
// GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
|
||||||
public ResultCode GetRegisterInfo(ServiceCtx context)
|
public ResultCode GetRegisterInfo(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(15)]
|
[Command(15)]
|
||||||
// GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
|
// GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
|
||||||
public ResultCode GetCommonInfo(ServiceCtx context)
|
public ResultCode GetCommonInfo(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(16)]
|
[Command(16)]
|
||||||
// GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
|
// GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
|
||||||
public ResultCode GetModelInfo(ServiceCtx context)
|
public ResultCode GetModelInfo(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(17)]
|
[Command(17)]
|
||||||
|
@ -308,7 +308,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
// GetApplicationAreaSize(bytes<8, 4>) -> u32
|
// GetApplicationAreaSize(bytes<8, 4>) -> u32
|
||||||
public ResultCode GetApplicationAreaSize(ServiceCtx context)
|
public ResultCode GetApplicationAreaSize(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(23)] // 3.0.0+
|
[Command(23)] // 3.0.0+
|
||||||
|
@ -334,7 +334,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
// RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
|
// RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
|
||||||
public ResultCode RecreateApplicationArea(ServiceCtx context)
|
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 _event0;
|
||||||
private KEvent _event1;
|
private KEvent _event1;
|
||||||
|
|
||||||
|
private int _event0Handle;
|
||||||
|
private int _event1Handle;
|
||||||
|
|
||||||
private uint _version;
|
private uint _version;
|
||||||
|
|
||||||
public IRequest(Horizon system, uint version)
|
public IRequest(Horizon system, uint version)
|
||||||
|
@ -50,17 +53,23 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
|
||||||
// GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
|
// GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
|
||||||
public ResultCode GetSystemEventReadableHandles(ServiceCtx context)
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
|
||||||
{
|
{
|
||||||
private readonly KEvent _event;
|
private readonly KEvent _event;
|
||||||
|
|
||||||
|
private int _eventHandle;
|
||||||
|
|
||||||
public IShopServiceAccessor(Horizon system)
|
public IShopServiceAccessor(Horizon system)
|
||||||
{
|
{
|
||||||
_event = new KEvent(system.KernelContext);
|
_event = new KEvent(system.KernelContext);
|
||||||
|
@ -22,12 +24,15 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
|
||||||
{
|
{
|
||||||
MakeObject(context, new IShopServiceAsync());
|
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);
|
Logger.Stub?.PrintStub(LogClass.ServiceNim);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
||||||
[Service("aoc:u")]
|
[Service("aoc:u")]
|
||||||
class IAddOnContentManager : IpcService
|
class IAddOnContentManager : IpcService
|
||||||
{
|
{
|
||||||
KEvent _addOnContentListChangedEvent;
|
private readonly KEvent _addOnContentListChangedEvent;
|
||||||
|
|
||||||
|
private int _addOnContentListChangedEventHandle;
|
||||||
|
|
||||||
public IAddOnContentManager(ServiceCtx context)
|
public IAddOnContentManager(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
@ -135,12 +137,15 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
||||||
{
|
{
|
||||||
// Official code seems to make an internal call to ns:am Cmd 84 GetDynamicCommitEvent()
|
// 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);
|
Logger.Stub?.PrintStub(LogClass.ServiceNs);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
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;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
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.NvHostCtrlGpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
@ -27,47 +27,45 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||||
private static Dictionary<string, Type> _deviceFileRegistry =
|
private static Dictionary<string, Type> _deviceFileRegistry =
|
||||||
new Dictionary<string, Type>()
|
new Dictionary<string, Type>()
|
||||||
{
|
{
|
||||||
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
||||||
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
||||||
{ "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
|
{ "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
|
||||||
{ "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) },
|
{ "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) },
|
||||||
{ "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) },
|
{ "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) },
|
||||||
//{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) },
|
//{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) },
|
||||||
{ "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) },
|
{ "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) },
|
||||||
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
||||||
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
||||||
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
||||||
};
|
};
|
||||||
|
|
||||||
private static IdDictionary _deviceFileIdRegistry = new IdDictionary();
|
private static IdDictionary _deviceFileIdRegistry = new IdDictionary();
|
||||||
|
|
||||||
private KProcess _owner;
|
private IVirtualMemoryManager _clientMemory;
|
||||||
|
private long _owner;
|
||||||
|
|
||||||
private bool _transferMemInitialized = false;
|
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)
|
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), typeof(IVirtualMemoryManager), typeof(long) });
|
||||||
{
|
|
||||||
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx) });
|
|
||||||
|
|
||||||
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);
|
return _deviceFileIdRegistry.Add(deviceFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -150,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||||
return NvResult.NotImplemented;
|
return NvResult.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceFile.Owner.Pid != _owner.Pid)
|
if (deviceFile.Owner != _owner)
|
||||||
{
|
{
|
||||||
return NvResult.AccessDenied;
|
return NvResult.AccessDenied;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +158,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||||
|
|
||||||
private NvResult EnsureInitialized()
|
private NvResult EnsureInitialized()
|
||||||
{
|
{
|
||||||
if (_owner == null)
|
if (_owner == 0)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.ServiceNv, "INvDrvServices is not initialized!");
|
Logger.Warning?.Print(LogClass.ServiceNv, "INvDrvServices is not initialized!");
|
||||||
|
|
||||||
|
@ -229,8 +227,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||||
if (errorCode == NvResult.Success)
|
if (errorCode == NvResult.Success)
|
||||||
{
|
{
|
||||||
long pathPtr = context.Request.SendBuff[0].Position;
|
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);
|
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.
|
// TODO: When transfer memory will be implemented, this could be removed.
|
||||||
_transferMemInitialized = true;
|
_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);
|
context.ResponseData.Write((uint)NvResult.Success);
|
||||||
|
|
||||||
|
@ -425,7 +428,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||||
// ForceSetClientPid(u64) -> u32 error_code
|
// ForceSetClientPid(u64) -> u32 error_code
|
||||||
public ResultCode ForceSetClientPid(ServiceCtx context)
|
public ResultCode ForceSetClientPid(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(8)]
|
[Command(8)]
|
||||||
|
@ -452,7 +455,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||||
// InitializeDevtools(u32, handle<copy>) -> u32 error_code;
|
// InitializeDevtools(u32, handle<copy>) -> u32 error_code;
|
||||||
public ResultCode InitializeDevtools(ServiceCtx context)
|
public ResultCode InitializeDevtools(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(11)] // 3.0.0+
|
[Command(11)] // 3.0.0+
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
@ -12,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices
|
||||||
abstract class NvDeviceFile
|
abstract class NvDeviceFile
|
||||||
{
|
{
|
||||||
public readonly ServiceCtx Context;
|
public readonly ServiceCtx Context;
|
||||||
public readonly KProcess Owner;
|
public readonly long Owner;
|
||||||
|
|
||||||
public string Path;
|
public string Path;
|
||||||
|
|
||||||
public NvDeviceFile(ServiceCtx context)
|
public NvDeviceFile(ServiceCtx context, long owner)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
Owner = context.Process;
|
Owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual NvInternalResult QueryEvent(out int eventHandle, uint eventId)
|
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.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
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>();
|
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)
|
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.NvHostCtrl;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -19,9 +20,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||||
private uint _submitTimeout;
|
private uint _submitTimeout;
|
||||||
private uint _timeslice;
|
private uint _timeslice;
|
||||||
|
|
||||||
private Switch _device;
|
private readonly Switch _device;
|
||||||
|
|
||||||
private Cpu.MemoryManager _memory;
|
private readonly IVirtualMemoryManager _memory;
|
||||||
|
|
||||||
public enum ResourcePolicy
|
public enum ResourcePolicy
|
||||||
{
|
{
|
||||||
|
@ -37,10 +38,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||||
|
|
||||||
private NvFence _channelSyncpoint;
|
private NvFence _channelSyncpoint;
|
||||||
|
|
||||||
public NvHostChannelDeviceFile(ServiceCtx context) : base(context)
|
public NvHostChannelDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||||
{
|
{
|
||||||
_device = context.Device;
|
_device = context.Device;
|
||||||
_memory = context.Memory;
|
_memory = memory;
|
||||||
_timeout = 3000;
|
_timeout = 3000;
|
||||||
_submitTimeout = 0;
|
_submitTimeout = 0;
|
||||||
_timeslice = 0;
|
_timeslice = 0;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
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 _smExceptionBptPauseReportEvent;
|
||||||
private KEvent _errorNotifierEvent;
|
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);
|
_smExceptionBptIntReportEvent = new KEvent(context.Device.System.KernelContext);
|
||||||
_smExceptionBptPauseReportEvent = 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 (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!");
|
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.NvDrvServices.NvHostCtrl.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Settings;
|
using Ryujinx.HLE.HOS.Services.Settings;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
|
||||||
private Switch _device;
|
private Switch _device;
|
||||||
private NvHostEvent[] _events;
|
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))
|
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 (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!");
|
throw new InvalidOperationException("Out of handles!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
|
||||||
private KEvent _errorEvent;
|
private KEvent _errorEvent;
|
||||||
private KEvent _unknownEvent;
|
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);
|
_errorEvent = new KEvent(context.Device.System.KernelContext);
|
||||||
_unknownEvent = 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 (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!");
|
throw new InvalidOperationException("Out of handles!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||||
{
|
{
|
||||||
private const int FlagNotFreedYet = 1;
|
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());
|
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
|
||||||
|
|
||||||
|
@ -244,9 +244,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||||
return dict.Add(map);
|
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;
|
return dict.Delete(handle) != null;
|
||||||
}
|
}
|
||||||
|
@ -254,14 +254,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||||
return false;
|
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)
|
if (map == null)
|
||||||
{
|
{
|
||||||
|
@ -270,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||||
|
|
||||||
if (map.DecrementRefCount() <= 0)
|
if (map.DecrementRefCount() <= 0)
|
||||||
{
|
{
|
||||||
DeleteMapWithHandle(process, handle);
|
DeleteMapWithHandle(pid, handle);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceNv, $"Deleted map {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);
|
return dict.GetData<NvMapHandle>(handle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
return ResultCode.InvalidAddress;
|
return ResultCode.InvalidAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
StructReader reader = new StructReader(context.Memory, nrrAddress);
|
StructReader reader = new StructReader(_owner.CpuMemory, nrrAddress);
|
||||||
NrrHeader header = reader.Read<NrrHeader>();
|
NrrHeader header = reader.Read<NrrHeader>();
|
||||||
|
|
||||||
if (header.Magic != NrrMagic)
|
if (header.Magic != NrrMagic)
|
||||||
|
@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
{
|
{
|
||||||
byte[] temp = new byte[0x20];
|
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);
|
hashes.Add(temp);
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
return ResultCode.InvalidAddress;
|
return ResultCode.InvalidAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint magic = context.Memory.Read<uint>(nroAddress + 0x10);
|
uint magic = _owner.CpuMemory.Read<uint>(nroAddress + 0x10);
|
||||||
uint nroFileSize = context.Memory.Read<uint>(nroAddress + 0x18);
|
uint nroFileSize = _owner.CpuMemory.Read<uint>(nroAddress + 0x18);
|
||||||
|
|
||||||
if (magic != NroMagic || nroSize != nroFileSize)
|
if (magic != NroMagic || nroSize != nroFileSize)
|
||||||
{
|
{
|
||||||
|
@ -141,7 +141,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
|
|
||||||
byte[] nroData = new byte[nroSize];
|
byte[] nroData = new byte[nroSize];
|
||||||
|
|
||||||
context.Memory.Read(nroAddress, nroData);
|
_owner.CpuMemory.Read(nroAddress, nroData);
|
||||||
|
|
||||||
byte[] nroHash = null;
|
byte[] nroHash = null;
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
// Check if everything is contiguous.
|
// Check if everything is contiguous.
|
||||||
if (nro.RoOffset != nro.TextOffset + nro.Text.Length ||
|
if (nro.RoOffset != nro.TextOffset + nro.Text.Length ||
|
||||||
nro.DataOffset != nro.RoOffset + nro.Ro.Length ||
|
nro.DataOffset != nro.RoOffset + nro.Ro.Length ||
|
||||||
nroFileSize != nro.DataOffset + nro.Data.Length)
|
nroFileSize != nro.DataOffset + nro.Data.Length)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidNro;
|
return ResultCode.InvalidNro;
|
||||||
}
|
}
|
||||||
|
@ -337,21 +337,21 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
|
|
||||||
KernelResult result;
|
KernelResult result;
|
||||||
|
|
||||||
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, MemoryPermission.ReadAndExecute);
|
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, KMemoryPermission.ReadAndExecute);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, MemoryPermission.Read);
|
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, KMemoryPermission.Read);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
return result;
|
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)
|
private ResultCode RemoveNrrInfo(long nrrAddress)
|
||||||
|
@ -420,9 +420,9 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
return (ResultCode)result;
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
// LoadNro(u64, u64, u64, u64, u64, pid) -> u64
|
// LoadNro(u64, u64, u64, u64, u64, pid) -> u64
|
||||||
public ResultCode LoadNro(ServiceCtx context)
|
public ResultCode LoadNro(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ResultCode result = IsInitialized(context.Process);
|
ResultCode result = IsInitialized(_owner.Pid);
|
||||||
|
|
||||||
// Zero
|
// Zero
|
||||||
context.RequestData.ReadUInt64();
|
context.RequestData.ReadUInt64();
|
||||||
|
@ -454,11 +454,11 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
result = MapNro(context.Process, info, out nroMappedAddress);
|
result = MapNro(_owner, info, out nroMappedAddress);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
result = (ResultCode)SetNroMemoryPermissions(context.Process, info.Executable, nroMappedAddress);
|
result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@ -479,7 +479,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
// UnloadNro(u64, u64, pid)
|
// UnloadNro(u64, u64, pid)
|
||||||
public ResultCode UnloadNro(ServiceCtx context)
|
public ResultCode UnloadNro(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ResultCode result = IsInitialized(context.Process);
|
ResultCode result = IsInitialized(_owner.Pid);
|
||||||
|
|
||||||
// Zero
|
// Zero
|
||||||
context.RequestData.ReadUInt64();
|
context.RequestData.ReadUInt64();
|
||||||
|
@ -503,7 +503,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
// LoadNrr(u64, u64, u64, pid)
|
// LoadNrr(u64, u64, u64, pid)
|
||||||
public ResultCode LoadNrr(ServiceCtx context)
|
public ResultCode LoadNrr(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ResultCode result = IsInitialized(context.Process);
|
ResultCode result = IsInitialized(_owner.Pid);
|
||||||
|
|
||||||
// pid placeholder, zero
|
// pid placeholder, zero
|
||||||
context.RequestData.ReadUInt64();
|
context.RequestData.ReadUInt64();
|
||||||
|
@ -536,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
// UnloadNrr(u64, u64, pid)
|
// UnloadNrr(u64, u64, pid)
|
||||||
public ResultCode UnloadNrr(ServiceCtx context)
|
public ResultCode UnloadNrr(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ResultCode result = IsInitialized(context.Process);
|
ResultCode result = IsInitialized(_owner.Pid);
|
||||||
|
|
||||||
// pid placeholder, zero
|
// pid placeholder, zero
|
||||||
context.RequestData.ReadUInt64();
|
context.RequestData.ReadUInt64();
|
||||||
|
@ -565,7 +565,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
||||||
return ResultCode.InvalidSession;
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
|
||||||
[Service("pl:s")] // 9.0.0+
|
[Service("pl:s")] // 9.0.0+
|
||||||
class ISharedFontManager : IpcService
|
class ISharedFontManager : IpcService
|
||||||
{
|
{
|
||||||
|
private int _fontSharedMemHandle;
|
||||||
|
|
||||||
public ISharedFontManager(ServiceCtx context) { }
|
public ISharedFontManager(ServiceCtx context) { }
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
|
@ -63,12 +65,15 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
|
||||||
{
|
{
|
||||||
context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager);
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +1,193 @@
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services
|
namespace Ryujinx.HLE.HOS.Services
|
||||||
{
|
{
|
||||||
class ServerBase
|
class ServerBase
|
||||||
{
|
{
|
||||||
private struct IpcRequest
|
// 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
|
||||||
public Switch Device { get; }
|
// not large enough.
|
||||||
public KProcess Process => Thread?.Owner;
|
private const int PointerBufferSize = 0x8000;
|
||||||
public KThread Thread { get; }
|
|
||||||
public KClientSession Session { get; }
|
|
||||||
public ulong MessagePtr { get; }
|
|
||||||
public ulong MessageSize { get; }
|
|
||||||
|
|
||||||
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;
|
_context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle);
|
||||||
Thread = thread;
|
|
||||||
Session = session;
|
AddPort(serverPortHandle, SmObject);
|
||||||
MessagePtr = messagePtr;
|
|
||||||
MessageSize = messageSize;
|
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;
|
int[] handles = _portHandles.ToArray();
|
||||||
Thread.Reschedule(ThreadSchedState.Running);
|
|
||||||
|
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;
|
private bool Process(int serverSessionHandle, ulong recvListAddr)
|
||||||
|
|
||||||
public ServerBase(string name)
|
|
||||||
{
|
{
|
||||||
_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)
|
byte[] reqData = new byte[messageSize];
|
||||||
{
|
|
||||||
_ipcProcessor.Add(new IpcRequest(device, thread, session, messagePtr, messageSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Process(IpcRequest message)
|
process.CpuMemory.Read(messagePtr, reqData);
|
||||||
{
|
|
||||||
byte[] reqData = new byte[message.MessageSize];
|
|
||||||
|
|
||||||
message.Process.CpuMemory.Read(message.MessagePtr, reqData);
|
IpcMessage request = new IpcMessage(reqData, (long)messagePtr);
|
||||||
|
|
||||||
IpcMessage request = new IpcMessage(reqData, (long)message.MessagePtr);
|
|
||||||
IpcMessage response = new IpcMessage();
|
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))
|
using (MemoryStream raw = new MemoryStream(request.RawData))
|
||||||
{
|
{
|
||||||
BinaryReader reqReader = new BinaryReader(raw);
|
BinaryReader reqReader = new BinaryReader(raw);
|
||||||
|
@ -71,17 +202,16 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
BinaryWriter resWriter = new BinaryWriter(resMs);
|
BinaryWriter resWriter = new BinaryWriter(resMs);
|
||||||
|
|
||||||
ServiceCtx context = new ServiceCtx(
|
ServiceCtx context = new ServiceCtx(
|
||||||
message.Device,
|
_context.Device,
|
||||||
message.Process,
|
process,
|
||||||
message.Process.CpuMemory,
|
process.CpuMemory,
|
||||||
message.Thread,
|
thread,
|
||||||
message.Session,
|
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
reqReader,
|
reqReader,
|
||||||
resWriter);
|
resWriter);
|
||||||
|
|
||||||
message.Session.Service.CallMethod(context);
|
_sessions[serverSessionHandle].CallMethod(context);
|
||||||
|
|
||||||
response.RawData = resMs.ToArray();
|
response.RawData = resMs.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -95,11 +225,11 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
switch (cmdId)
|
switch (cmdId)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
request = FillResponse(response, 0, message.Session.Service.ConvertToDomain());
|
request = FillResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
request = FillResponse(response, 0, 0x1000);
|
request = FillResponse(response, 0, PointerBufferSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: Whats the difference between IpcDuplicateSession/Ex?
|
// TODO: Whats the difference between IpcDuplicateSession/Ex?
|
||||||
|
@ -107,12 +237,11 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
case 4:
|
case 4:
|
||||||
int unknown = reqReader.ReadInt32();
|
int unknown = reqReader.ReadInt32();
|
||||||
|
|
||||||
if (message.Process.HandleTable.GenerateHandle(message.Session, out int handle) != KernelResult.Success)
|
_context.Syscall.CreateSession(false, 0, out int dupServerSessionHandle, out int dupClientSessionHandle);
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Out of handles!");
|
|
||||||
}
|
|
||||||
|
|
||||||
response.HandleDesc = IpcHandleDesc.MakeMove(handle);
|
AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]);
|
||||||
|
|
||||||
|
response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle);
|
||||||
|
|
||||||
request = FillResponse(response, 0);
|
request = FillResponse(response, 0);
|
||||||
|
|
||||||
|
@ -123,18 +252,24 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
}
|
}
|
||||||
else if (request.Type == IpcMessageType.CloseSession)
|
else if (request.Type == IpcMessageType.CloseSession)
|
||||||
{
|
{
|
||||||
message.SignalDone(KernelResult.PortRemoteClosed);
|
_context.Syscall.CloseHandle(serverSessionHandle);
|
||||||
return;
|
_sessionHandles.Remove(serverSessionHandle);
|
||||||
|
IpcService service = _sessions[serverSessionHandle];
|
||||||
|
if (service is IDisposable disposableObj)
|
||||||
|
{
|
||||||
|
disposableObj.Dispose();
|
||||||
|
}
|
||||||
|
_sessions.Remove(serverSessionHandle);
|
||||||
|
shouldReply = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new NotImplementedException(request.Type.ToString());
|
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)
|
private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||||
using System;
|
using System;
|
||||||
|
@ -11,18 +12,17 @@ using System.Reflection;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sm
|
namespace Ryujinx.HLE.HOS.Services.Sm
|
||||||
{
|
{
|
||||||
[Service("sm:")]
|
|
||||||
class IUserInterface : IpcService
|
class IUserInterface : IpcService
|
||||||
{
|
{
|
||||||
private Dictionary<string, Type> _services;
|
private Dictionary<string, Type> _services;
|
||||||
|
|
||||||
private ConcurrentDictionary<string, KPort> _registeredServices;
|
private readonly ConcurrentDictionary<string, KPort> _registeredServices;
|
||||||
|
|
||||||
private readonly ServerBase _commonServer;
|
private readonly ServerBase _commonServer;
|
||||||
|
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
|
|
||||||
public IUserInterface(ServiceCtx context = null) : base(new ServerBase("SmServer"))
|
public IUserInterface(KernelContext context)
|
||||||
{
|
{
|
||||||
_registeredServices = new ConcurrentDictionary<string, KPort>();
|
_registeredServices = new ConcurrentDictionary<string, KPort>();
|
||||||
|
|
||||||
|
@ -31,18 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||||
.Select(service => (((ServiceAttribute)service).Name, type)))
|
.Select(service => (((ServiceAttribute)service).Name, type)))
|
||||||
.ToDictionary(service => service.Name, service => service.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)
|
_commonServer = new ServerBase(context, "CommonServer");
|
||||||
{
|
|
||||||
KPort port = new KPort(system.KernelContext, 256, false, 0);
|
|
||||||
|
|
||||||
port.ClientPort.SetName("sm:");
|
|
||||||
|
|
||||||
IUserInterface smService = new IUserInterface();
|
|
||||||
|
|
||||||
port.ClientPort.Service = smService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
|
@ -92,16 +83,13 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||||
: (IpcService)Activator.CreateInstance(type, context);
|
: (IpcService)Activator.CreateInstance(type, context);
|
||||||
|
|
||||||
service.TrySetServer(_commonServer);
|
service.TrySetServer(_commonServer);
|
||||||
|
service.Server.AddSessionObj(session.ServerSession, service);
|
||||||
session.ClientSession.Service = service;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ServiceConfiguration.IgnoreMissingServices)
|
if (ServiceConfiguration.IgnoreMissingServices)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
|
Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
|
||||||
|
|
||||||
session.ClientSession.Service = new DummyService(name);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -142,7 +130,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||||
|
|
||||||
int maxSessions = context.RequestData.ReadInt32();
|
int maxSessions = context.RequestData.ReadInt32();
|
||||||
|
|
||||||
if (name == string.Empty)
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidName;
|
return ResultCode.InvalidName;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +173,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||||
|
|
||||||
int maxSessions = context.RequestData.ReadInt32();
|
int maxSessions = context.RequestData.ReadInt32();
|
||||||
|
|
||||||
if (name == string.Empty)
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidName;
|
return ResultCode.InvalidName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
|
||||||
private List<BsdSocket> _sockets = new List<BsdSocket>();
|
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;
|
_isPrivileged = isPrivileged;
|
||||||
}
|
}
|
||||||
|
@ -247,6 +247,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceBsd);
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,14 +118,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
|
||||||
// ImportSettings(u32, buffer<unknown, 5>) -> buffer<unknown, 6>
|
// ImportSettings(u32, buffer<unknown, 5>) -> buffer<unknown, 6>
|
||||||
public ResultCode ImportSettings(ServiceCtx context)
|
public ResultCode ImportSettings(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(15)]
|
[Command(15)]
|
||||||
// Unknown(bytes<1>)
|
// Unknown(bytes<1>)
|
||||||
public ResultCode Unknown(ServiceCtx context)
|
public ResultCode Unknown(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(20)]
|
[Command(20)]
|
||||||
|
@ -164,49 +164,49 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
|
||||||
// GetNasServiceSetting(buffer<unknown<0x10>, 0x15>) -> buffer<unknown<0x108>, 0x16>
|
// GetNasServiceSetting(buffer<unknown<0x10>, 0x15>) -> buffer<unknown<0x108>, 0x16>
|
||||||
public ResultCode GetNasServiceSetting(ServiceCtx context)
|
public ResultCode GetNasServiceSetting(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(31)]
|
[Command(31)]
|
||||||
// GetNasServiceSettingEx(buffer<unknown<0x10>, 0x15>) -> (u32, buffer<unknown<0x108>, 0x16>)
|
// GetNasServiceSettingEx(buffer<unknown<0x10>, 0x15>) -> (u32, buffer<unknown<0x108>, 0x16>)
|
||||||
public ResultCode GetNasServiceSettingEx(ServiceCtx context)
|
public ResultCode GetNasServiceSettingEx(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(40)]
|
[Command(40)]
|
||||||
// GetNasRequestFqdn() -> buffer<unknown<0x100>, 0x16>
|
// GetNasRequestFqdn() -> buffer<unknown<0x100>, 0x16>
|
||||||
public ResultCode GetNasRequestFqdn(ServiceCtx context)
|
public ResultCode GetNasRequestFqdn(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(41)]
|
[Command(41)]
|
||||||
// GetNasRequestFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
|
// GetNasRequestFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
|
||||||
public ResultCode GetNasRequestFqdnEx(ServiceCtx context)
|
public ResultCode GetNasRequestFqdnEx(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(42)]
|
[Command(42)]
|
||||||
// GetNasApiFqdn() -> buffer<unknown<0x100>, 0x16>
|
// GetNasApiFqdn() -> buffer<unknown<0x100>, 0x16>
|
||||||
public ResultCode GetNasApiFqdn(ServiceCtx context)
|
public ResultCode GetNasApiFqdn(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(43)]
|
[Command(43)]
|
||||||
// GetNasApiFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
|
// GetNasApiFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
|
||||||
public ResultCode GetNasApiFqdnEx(ServiceCtx context)
|
public ResultCode GetNasApiFqdnEx(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(50)]
|
[Command(50)]
|
||||||
// GetCurrentSetting() -> buffer<unknown<0x12bf0>, 0x16>
|
// GetCurrentSetting() -> buffer<unknown<0x12bf0>, 0x16>
|
||||||
public ResultCode GetCurrentSetting(ServiceCtx context)
|
public ResultCode GetCurrentSetting(ServiceCtx context)
|
||||||
{
|
{
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(60)]
|
[Command(60)]
|
||||||
|
@ -262,7 +262,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
|
||||||
// IsChangeEnvironmentIdentifierDisabled() -> bytes<1>
|
// IsChangeEnvironmentIdentifierDisabled() -> bytes<1>
|
||||||
public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context)
|
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);
|
producer = new BufferQueueProducer(core);
|
||||||
consumer = new BufferQueueConsumer(core);
|
consumer = new BufferQueueConsumer(core);
|
||||||
|
|
||||||
|
return core;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using Ryujinx.Common.Logging;
|
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.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||||
using System;
|
using System;
|
||||||
|
@ -40,11 +40,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
private KEvent _waitBufferFreeEvent;
|
private KEvent _waitBufferFreeEvent;
|
||||||
private KEvent _frameAvailableEvent;
|
private KEvent _frameAvailableEvent;
|
||||||
|
|
||||||
public KProcess Owner { get; }
|
public long Owner { get; }
|
||||||
|
|
||||||
|
public bool Active { get; private set; }
|
||||||
|
|
||||||
public const int BufferHistoryArraySize = 8;
|
public const int BufferHistoryArraySize = 8;
|
||||||
|
|
||||||
public BufferQueueCore(Switch device, KProcess process)
|
public BufferQueueCore(Switch device, long pid)
|
||||||
{
|
{
|
||||||
Slots = new BufferSlotArray();
|
Slots = new BufferSlotArray();
|
||||||
IsAbandoned = false;
|
IsAbandoned = false;
|
||||||
|
@ -70,7 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
_waitBufferFreeEvent = new KEvent(device.System.KernelContext);
|
_waitBufferFreeEvent = new KEvent(device.System.KernelContext);
|
||||||
_frameAvailableEvent = new KEvent(device.System.KernelContext);
|
_frameAvailableEvent = new KEvent(device.System.KernelContext);
|
||||||
|
|
||||||
Owner = process;
|
Owner = pid;
|
||||||
|
|
||||||
|
Active = true;
|
||||||
|
|
||||||
BufferHistory = new BufferInfo[BufferHistoryArraySize];
|
BufferHistory = new BufferInfo[BufferHistoryArraySize];
|
||||||
EnableExternalEvent = true;
|
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.
|
// 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()
|
public void SignalDequeueEvent()
|
||||||
{
|
{
|
||||||
|
@ -170,7 +184,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
public void WaitDequeueEvent()
|
public void WaitDequeueEvent()
|
||||||
{
|
{
|
||||||
Monitor.Wait(Lock);
|
Monitor.Exit(Lock);
|
||||||
|
|
||||||
|
KernelStatic.YieldUntilCompletion(WaitForLock);
|
||||||
|
|
||||||
|
Monitor.Enter(Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignalIsAllocatingEvent()
|
public void SignalIsAllocatingEvent()
|
||||||
|
@ -180,7 +198,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
public void WaitIsAllocatingEvent()
|
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)
|
public void FreeBufferLocked(int slot)
|
||||||
|
|
|
@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.WaitDequeueEvent();
|
Core.WaitDequeueEvent();
|
||||||
|
|
||||||
|
if (!Core.Active)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
{
|
{
|
||||||
abstract class IHOSBinderDriver : IpcService
|
abstract class IHOSBinderDriver : IpcService
|
||||||
{
|
{
|
||||||
public IHOSBinderDriver() {}
|
public IHOSBinderDriver() { }
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
// TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>
|
// TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu;
|
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.NvDrvServices.NvMap;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -40,7 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
public int ProducerBinderId;
|
public int ProducerBinderId;
|
||||||
public IGraphicBufferProducer Producer;
|
public IGraphicBufferProducer Producer;
|
||||||
public BufferItemConsumer Consumer;
|
public BufferItemConsumer Consumer;
|
||||||
public KProcess Owner;
|
public BufferQueueCore Core;
|
||||||
|
public long Owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TextureCallbackInformation
|
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;
|
bool needCreate;
|
||||||
|
|
||||||
|
@ -95,13 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
if (needCreate)
|
if (needCreate)
|
||||||
{
|
{
|
||||||
CreateLayerFromId(process, layerId);
|
CreateLayerFromId(pid, layerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetProducerByLayerId(layerId);
|
return GetProducerByLayerId(layerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IGraphicBufferProducer CreateLayer(KProcess process, out long layerId)
|
public IGraphicBufferProducer CreateLayer(long pid, out long layerId)
|
||||||
{
|
{
|
||||||
layerId = 1;
|
layerId = 1;
|
||||||
|
|
||||||
|
@ -116,25 +114,26 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateLayerFromId(process, layerId);
|
CreateLayerFromId(pid, layerId);
|
||||||
|
|
||||||
return GetProducerByLayerId(layerId);
|
return GetProducerByLayerId(layerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateLayerFromId(KProcess process, long layerId)
|
private void CreateLayerFromId(long pid, long layerId)
|
||||||
{
|
{
|
||||||
lock (Lock)
|
lock (Lock)
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.SurfaceFlinger, $"Creating layer {layerId}");
|
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
|
_layers.Add(layerId, new Layer
|
||||||
{
|
{
|
||||||
ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
|
ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
|
||||||
Producer = producer,
|
Producer = producer,
|
||||||
Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
|
Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
|
||||||
Owner = process
|
Core = core,
|
||||||
|
Owner = pid
|
||||||
});
|
});
|
||||||
|
|
||||||
LastId = layerId;
|
LastId = layerId;
|
||||||
|
@ -345,6 +344,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
|
|
||||||
|
foreach (Layer layer in _layers.Values)
|
||||||
|
{
|
||||||
|
layer.Core.PrepareForExit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnFrameAvailable(ref BufferItem item)
|
public void OnFrameAvailable(ref BufferItem item)
|
||||||
|
|
|
@ -42,23 +42,23 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
Buffer = parcel.ReadUnmanagedType<NvGraphicBuffer>();
|
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++)
|
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++)
|
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 IStaticServiceForPsc _inner;
|
||||||
private TimePermissions _permissions;
|
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;
|
_permissions = permissions;
|
||||||
_inner = new IStaticServiceForPsc(context, permissions);
|
_inner = new IStaticServiceForPsc(context, permissions);
|
||||||
|
_inner.TrySetServer(Server);
|
||||||
|
_inner.SetParent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
|
|
|
@ -149,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public ResultCode Unknown50(ServiceCtx context)
|
public ResultCode Unknown50(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO: figure out the usage of this event
|
// TODO: figure out the usage of this event
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(51)]
|
[Command(51)]
|
||||||
|
@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public ResultCode Unknown51(ServiceCtx context)
|
public ResultCode Unknown51(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO: figure out the usage of this event
|
// TODO: figure out the usage of this event
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(52)]
|
[Command(52)]
|
||||||
|
@ -165,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public ResultCode Unknown52(ServiceCtx context)
|
public ResultCode Unknown52(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO: figure out the usage of this event
|
// TODO: figure out the usage of this event
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(60)]
|
[Command(60)]
|
||||||
|
@ -201,7 +201,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public ResultCode GetAlarmRegistrationEvent(ServiceCtx context)
|
public ResultCode GetAlarmRegistrationEvent(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(201)]
|
[Command(201)]
|
||||||
|
@ -209,7 +209,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public ResultCode UpdateSteadyAlarms(ServiceCtx context)
|
public ResultCode UpdateSteadyAlarms(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(202)]
|
[Command(202)]
|
||||||
|
@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public ResultCode TryGetNextSteadyClockAlarmSnapshot(ServiceCtx context)
|
public ResultCode TryGetNextSteadyClockAlarmSnapshot(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
throw new ServiceNotImplementedException(context);
|
throw new ServiceNotImplementedException(this, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
[Service("vi:u")]
|
[Service("vi:u")]
|
||||||
class IApplicationRootService : IpcService
|
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(context.Device.System.KernelContext, "ViServerU")) { }
|
||||||
public IApplicationRootService(ServiceCtx context) : base(new ServerBase("ViServerU")) { }
|
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
class IManagerRootService : IpcService
|
class IManagerRootService : IpcService
|
||||||
{
|
{
|
||||||
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
|
// 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)]
|
[Command(2)]
|
||||||
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
class ISystemRootService : IpcService
|
class ISystemRootService : IpcService
|
||||||
{
|
{
|
||||||
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
|
// 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)]
|
[Command(1)]
|
||||||
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue