mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2024-12-22 18:05:46 +00:00
IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel (#1458)
* IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel * Fix for applet transfer memory + some nits * Keep handles if possible to avoid server handle table exhaustion * Fix IPC ZeroFill bug * am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer CreateManagedDisplaySeparableLayer is requires since 10.x+ when appletResourceUserId != 0 * Make it exit properly * Make ServiceNotImplementedException show the full message again * Allow yielding execution to avoid starving other threads * Only wait if active * Merge IVirtualMemoryManager and IAddressSpaceManager * Fix Ro loading data from the wrong process Co-authored-by: Thog <me@thog.eu>
This commit is contained in:
parent
461c24092a
commit
cf6cd71488
115 changed files with 2356 additions and 1088 deletions
|
@ -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<InstExceptionEventArgs> Break;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
//
|
||||
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -65,7 +65,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||
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)
|
||||
{
|
||||
|
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||
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)
|
||||
{
|
||||
|
@ -175,8 +175,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||
}
|
||||
else
|
||||
{
|
||||
MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
||||
MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
||||
ZeroFill(context.MemoryManager, BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
||||
ZeroFill(context.MemoryManager, BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
|
||||
|
||||
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.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||
|
||||
public List<ICommand> Commands { get; }
|
||||
|
||||
public MemoryManager MemoryManager { get; }
|
||||
public IVirtualMemoryManager MemoryManager { get; }
|
||||
|
||||
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;
|
||||
SampleRate = sampleRate;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
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;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||
|
@ -33,22 +33,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
|||
public uint WriteOffset;
|
||||
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);
|
||||
}
|
||||
|
||||
public static uint GetWriteOffset(MemoryManager manager, ulong bufferAddress)
|
||||
public static uint GetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -31,7 +31,7 @@ using Ryujinx.Audio.Renderer.Server.Voice;
|
|||
using Ryujinx.Audio.Renderer.Utils;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
|
@ -87,7 +87,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||
|
||||
private Memory<byte> _performanceBuffer;
|
||||
|
||||
public MemoryManager MemoryManager { get; private set; }
|
||||
public IVirtualMemoryManager MemoryManager { get; private set; }
|
||||
|
||||
private ulong _elapsedFrameCount;
|
||||
private ulong _renderingStartTick;
|
||||
|
@ -96,14 +96,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||
|
||||
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
|
||||
{
|
||||
_manager = manager;
|
||||
_terminationEvent = new ManualResetEvent(false);
|
||||
_manager = manager;
|
||||
_terminationEvent = new ManualResetEvent(false);
|
||||
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||
_voiceContext = new VoiceContext();
|
||||
_mixContext = new MixContext();
|
||||
_sinkContext = new SinkContext();
|
||||
_splitterContext = new SplitterContext();
|
||||
_effectContext = new EffectContext();
|
||||
_voiceContext = new VoiceContext();
|
||||
_mixContext = new MixContext();
|
||||
_sinkContext = new SinkContext();
|
||||
_splitterContext = new SplitterContext();
|
||||
_effectContext = new EffectContext();
|
||||
|
||||
_commandProcessingTimeEstimator = null;
|
||||
_systemEvent = systemEvent;
|
||||
|
@ -113,7 +113,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||
_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))
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Dsp;
|
|||
using Ryujinx.Audio.Renderer.Integration;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
@ -288,7 +288,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||
/// <param name="workBufferSize">The guest work buffer size.</param>
|
||||
/// <param name="processHandle">The process handle of the application.</param>
|
||||
/// <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();
|
||||
|
||||
|
@ -321,6 +321,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
lock (_audioProcessorLock)
|
||||
{
|
||||
if (_isRunning)
|
||||
{
|
||||
StopLocked();
|
||||
}
|
||||
}
|
||||
|
||||
Processor.Dispose();
|
||||
|
||||
foreach (HardwareDevice device in OutputDevices)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -7,7 +8,7 @@ namespace Ryujinx.Cpu
|
|||
{
|
||||
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);
|
||||
|
||||
|
@ -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>();
|
||||
|
||||
|
@ -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>();
|
||||
|
||||
|
@ -50,7 +51,7 @@ namespace Ryujinx.Cpu
|
|||
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())
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Cpu
|
|||
/// <summary>
|
||||
/// Represents a CPU memory manager.
|
||||
/// </summary>
|
||||
public sealed class MemoryManager : IMemoryManager, IDisposable, IVirtualMemoryManager
|
||||
public sealed class MemoryManager : IMemoryManager, IVirtualMemoryManager, IDisposable
|
||||
{
|
||||
public const int PageBits = 12;
|
||||
public const int PageSize = 1 << PageBits;
|
||||
|
@ -468,6 +468,11 @@ namespace Ryujinx.Cpu
|
|||
/// <returns>True if the entire range is mapped, false otherwise</returns>
|
||||
public bool IsRangeMapped(ulong va, ulong size)
|
||||
{
|
||||
if (size == 0UL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
||||
|
||||
va &= ~(ulong)PageMask;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Tracking;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -12,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
class PhysicalMemory
|
||||
{
|
||||
public const int PageSize = Cpu.MemoryManager.PageSize;
|
||||
public const int PageSize = 0x1000;
|
||||
|
||||
private readonly Cpu.MemoryManager _cpuMemory;
|
||||
|
||||
|
|
|
@ -14,28 +14,31 @@ namespace Ryujinx.HLE.Exceptions
|
|||
[Serializable]
|
||||
internal class ServiceNotImplementedException : Exception
|
||||
{
|
||||
public IIpcService Service { get; }
|
||||
public ServiceCtx Context { get; }
|
||||
public IpcMessage Request { get; }
|
||||
|
||||
public ServiceNotImplementedException(ServiceCtx context)
|
||||
: this(context, "The service call is not implemented.")
|
||||
public ServiceNotImplementedException(IIpcService service, ServiceCtx context)
|
||||
: 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)
|
||||
{
|
||||
Service = service;
|
||||
Context = context;
|
||||
Request = context.Request;
|
||||
}
|
||||
|
||||
public ServiceNotImplementedException(ServiceCtx context, string message, Exception inner)
|
||||
public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
Service = service;
|
||||
Context = context;
|
||||
Request = context.Request;
|
||||
}
|
||||
|
||||
protected ServiceNotImplementedException(SerializationInfo info, StreamingContext context)
|
||||
protected ServiceNotImplementedException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
|
||||
|
@ -59,17 +62,16 @@ namespace Ryujinx.HLE.Exceptions
|
|||
|
||||
if (callingType != null && callingMethod != null)
|
||||
{
|
||||
var ipcService = Context.Session.Service;
|
||||
var ipcCommands = ipcService.Commands;
|
||||
var ipcCommands = Service.Commands;
|
||||
|
||||
// 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 ipcMethod = ipcHandler.Value;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
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);
|
||||
timePageList.AddRange(timePa, TimeSize / KMemoryManager.PageSize);
|
||||
|
||||
HidSharedMem = new KSharedMemory(KernelContext, hidPageList, 0, 0, MemoryPermission.Read);
|
||||
FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, MemoryPermission.Read);
|
||||
IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, MemoryPermission.Read);
|
||||
HidSharedMem = new KSharedMemory(KernelContext, hidPageList, 0, 0, KMemoryPermission.Read);
|
||||
FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, KMemoryPermission.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);
|
||||
|
||||
|
@ -134,8 +134,6 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
Font = new SharedFontManager(device, fontPa - DramMemoryMap.DramBase);
|
||||
|
||||
IUserInterface.InitializePort(this);
|
||||
|
||||
VsyncEvent = new KEvent(KernelContext);
|
||||
|
||||
DisplayResolutionChangeEvent = new KEvent(KernelContext);
|
||||
|
@ -224,6 +222,16 @@ namespace Ryujinx.HLE.HOS
|
|||
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)
|
||||
{
|
||||
using IStorage kipFile = new LocalStorage(kipPath, FileAccess.Read);
|
||||
|
|
|
@ -84,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
|
||||
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
||||
|
||||
if (rawDataSize != 0)
|
||||
{
|
||||
rawDataSize -= (int)pad0;
|
||||
}
|
||||
|
||||
reader.BaseStream.Seek(pad0, SeekOrigin.Current);
|
||||
|
||||
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())
|
||||
{
|
||||
|
@ -131,7 +136,11 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
|
||||
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
|
||||
// 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;
|
||||
|
||||
word1 = dataLength & 0x3ff;
|
||||
word1 = (dataLength & 0x3ff) | (2 << 10);
|
||||
|
||||
if (HandleDesc != null)
|
||||
{
|
||||
|
@ -151,14 +160,22 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
writer.Write(word1);
|
||||
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);
|
||||
|
||||
if (RawData != null)
|
||||
{
|
||||
writer.Write(RawData);
|
||||
ms.Seek(rawLength - RawData.Length, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
writer.Write(new byte[pad1]);
|
||||
writer.Write(recvListAddr);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
|
|
@ -8,6 +8,13 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
public int Index { 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)
|
||||
{
|
||||
long word0 = reader.ReadUInt32();
|
||||
|
@ -22,5 +29,25 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
|
||||
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 Size { get; private set; }
|
||||
|
||||
public IpcRecvListBuffDesc(long position, long size)
|
||||
{
|
||||
Position = position;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public IpcRecvListBuffDesc(BinaryReader reader)
|
||||
{
|
||||
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,
|
||||
stateMask,
|
||||
stateMask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
attributeMask,
|
||||
MemoryAttribute.None,
|
||||
desc.ServerAddress);
|
||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
clientEndAddr - clientEndAddrTruncated,
|
||||
stateMask,
|
||||
stateMask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
attributeMask,
|
||||
MemoryAttribute.None,
|
||||
serverEndAddrTruncated);
|
||||
|
|
|
@ -14,10 +14,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
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)
|
||||
{
|
||||
_maxSessions = maxSessions;
|
||||
|
@ -45,11 +41,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
KSession session = new KSession(KernelContext, this);
|
||||
|
||||
if (Service != null)
|
||||
{
|
||||
session.ClientSession.Service = Service;
|
||||
}
|
||||
|
||||
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
|
|
@ -16,10 +16,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
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)
|
||||
{
|
||||
_parent = parent;
|
||||
|
@ -84,11 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
{
|
||||
_parent.DisconnectClient();
|
||||
_parent.DecrementReferenceCount();
|
||||
|
||||
if (Service is IDisposable disposableObj)
|
||||
{
|
||||
disposableObj.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -430,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
descriptor.BufferAddress,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryPermission.Read,
|
||||
KMemoryPermission.Read,
|
||||
MemoryAttribute.Uncached,
|
||||
MemoryAttribute.None);
|
||||
|
||||
|
@ -473,9 +473,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
bool notReceiveDesc = isSendDesc || isExchangeDesc;
|
||||
bool isReceiveDesc = !notReceiveDesc;
|
||||
|
||||
MemoryPermission permission = index >= clientHeader.SendBuffersCount
|
||||
? MemoryPermission.ReadAndWrite
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permission = index >= clientHeader.SendBuffersCount
|
||||
? KMemoryPermission.ReadAndWrite
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
uint sizeHigh4 = (descWord2 >> 24) & 0xf;
|
||||
|
||||
|
@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
||||
{
|
||||
MemoryPermission permission = clientMsg.IsCustom
|
||||
? MemoryPermission.None
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permission = clientMsg.IsCustom
|
||||
? KMemoryPermission.None
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
|
||||
copyDst,
|
||||
|
@ -795,7 +795,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
descriptor.BufferSize,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryPermission.Read,
|
||||
KMemoryPermission.Read,
|
||||
MemoryAttribute.Uncached,
|
||||
MemoryAttribute.None,
|
||||
descriptor.BufferAddress);
|
||||
|
@ -849,9 +849,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
||||
{
|
||||
MemoryPermission permission = clientMsg.IsCustom
|
||||
? MemoryPermission.None
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permission = clientMsg.IsCustom
|
||||
? KMemoryPermission.None
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
|
||||
copyDst,
|
||||
|
@ -898,11 +898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
return new MessageHeader(word0, word1, word2);
|
||||
}
|
||||
|
||||
private KernelResult GetCopyObjectHandle(
|
||||
KThread srcThread,
|
||||
KProcess dstProcess,
|
||||
int srcHandle,
|
||||
out int dstHandle)
|
||||
private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
|
||||
{
|
||||
dstHandle = 0;
|
||||
|
||||
|
@ -933,11 +929,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
}
|
||||
}
|
||||
|
||||
private KernelResult GetMoveObjectHandle(
|
||||
KProcess srcProcess,
|
||||
KProcess dstProcess,
|
||||
int srcHandle,
|
||||
out int dstHandle)
|
||||
private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
|
||||
{
|
||||
dstHandle = 0;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KSession : KAutoObject, IDisposable
|
||||
class KSession : KAutoObject
|
||||
{
|
||||
public KServerSession ServerSession { 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()
|
||||
{
|
||||
if (_hasBeenInitialized)
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
Device = device;
|
||||
Memory = memory;
|
||||
|
||||
Syscall = new Syscall(device, this);
|
||||
Syscall = new Syscall(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 MemoryState State { get; private set; }
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
public KMemoryPermission Permission { 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 DeviceRefCount { get; private set; }
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong baseAddress,
|
||||
ulong pagesCount,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attribute,
|
||||
int ipcRefCount = 0,
|
||||
int deviceRefCount = 0)
|
||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
DeviceRefCount = deviceRefCount;
|
||||
}
|
||||
|
||||
public void SetState(MemoryPermission permission, MemoryState state, MemoryAttribute attribute)
|
||||
public void SetState(KMemoryPermission permission, MemoryState state, MemoryAttribute attribute)
|
||||
{
|
||||
Permission = permission;
|
||||
State = state;
|
||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
Attribute |= attribute;
|
||||
}
|
||||
|
||||
public void SetIpcMappingPermission(MemoryPermission newPermission)
|
||||
public void SetIpcMappingPermission(KMemoryPermission newPermission)
|
||||
{
|
||||
int oldIpcRefCount = IpcRefCount++;
|
||||
|
||||
|
@ -54,8 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
SourcePermission = Permission;
|
||||
|
||||
Permission &= ~MemoryPermission.ReadAndWrite;
|
||||
Permission |= MemoryPermission.ReadAndWrite & newPermission;
|
||||
Permission &= ~KMemoryPermission.ReadAndWrite;
|
||||
Permission |= KMemoryPermission.ReadAndWrite & newPermission;
|
||||
}
|
||||
|
||||
Attribute |= MemoryAttribute.IpcMapped;
|
||||
|
@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
Permission = SourcePermission;
|
||||
|
||||
SourcePermission = MemoryPermission.None;
|
||||
SourcePermission = KMemoryPermission.None;
|
||||
|
||||
Attribute &= ~MemoryAttribute.IpcMapped;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
public ulong Size { get; }
|
||||
|
||||
public MemoryState State { get; }
|
||||
public MemoryPermission Permission { get; }
|
||||
public KMemoryPermission Permission { get; }
|
||||
public MemoryAttribute Attribute { get; }
|
||||
public MemoryPermission SourcePermission { get; }
|
||||
public KMemoryPermission SourcePermission { get; }
|
||||
|
||||
public int IpcRefCount { get; }
|
||||
public int DeviceRefCount { get; }
|
||||
|
@ -17,9 +17,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
ulong size,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attribute,
|
||||
MemoryPermission sourcePermission,
|
||||
KMemoryPermission sourcePermission,
|
||||
int ipcRefCount,
|
||||
int deviceRefCount)
|
||||
{
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
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.
|
||||
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 AddrSpaceEnd { get; private set; }
|
||||
|
@ -73,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
private MersenneTwister _randomNumberGenerator;
|
||||
|
||||
public KMemoryManager(KernelContext context, MemoryManager cpuMemory)
|
||||
public KMemoryManager(KernelContext context, IVirtualMemoryManager cpuMemory)
|
||||
{
|
||||
_context = context;
|
||||
_cpuMemory = cpuMemory;
|
||||
|
@ -352,7 +353,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
addrSpaceStart,
|
||||
addrSpacePagesCount,
|
||||
MemoryState.Unmapped,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.None));
|
||||
|
||||
return KernelResult.Success;
|
||||
|
@ -362,13 +363,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
KPageList pageList,
|
||||
MemoryState state,
|
||||
MemoryPermission permission)
|
||||
KMemoryPermission permission)
|
||||
{
|
||||
ulong pagesCount = pageList.GetPagesCount();
|
||||
|
||||
ulong size = pagesCount * PageSize;
|
||||
|
||||
if (!ValidateRegionForState(address, size, state))
|
||||
if (!CanContain(address, size, state))
|
||||
{
|
||||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
@ -437,8 +438,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
stateExpected,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
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.
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult MapIoMemory(long address, long size, MemoryPermission permission)
|
||||
public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
|
||||
{
|
||||
// TODO.
|
||||
return KernelResult.Success;
|
||||
|
@ -487,7 +488,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong regionStart,
|
||||
ulong regionPagesCount,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
out ulong address)
|
||||
{
|
||||
address = 0;
|
||||
|
@ -496,7 +497,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
ulong regionEndAddr = regionStart + regionSize;
|
||||
|
||||
if (!ValidateRegionForState(regionStart, regionSize, state))
|
||||
if (!CanContain(regionStart, regionSize, state))
|
||||
{
|
||||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
@ -547,11 +548,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
ulong pagesCount,
|
||||
MemoryState state,
|
||||
MemoryPermission permission)
|
||||
KMemoryPermission permission)
|
||||
{
|
||||
ulong size = pagesCount * PageSize;
|
||||
|
||||
if (!ValidateRegionForState(address, size, state))
|
||||
if (!CanContain(address, size, state))
|
||||
{
|
||||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
@ -596,13 +597,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Heap,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out MemoryState state,
|
||||
out MemoryPermission permission,
|
||||
out KMemoryPermission permission,
|
||||
out _);
|
||||
|
||||
success &= IsUnmapped(dst, size);
|
||||
|
@ -618,14 +619,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
AddVaRangeToPageList(pageList, src, pagesCount);
|
||||
|
||||
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
|
||||
KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = MapPages(dst, pageList, MemoryPermission.None);
|
||||
result = MapPages(dst, pageList, KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -634,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return result;
|
||||
}
|
||||
|
||||
InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed);
|
||||
InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
|
||||
InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
|
||||
|
||||
return KernelResult.Success;
|
||||
|
@ -657,8 +658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Heap,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.Borrowed,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -671,8 +672,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
PageSize,
|
||||
MemoryState.UnmapProcessCodeMemoryAllowed,
|
||||
MemoryState.UnmapProcessCodeMemoryAllowed,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -685,8 +686,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
state,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None);
|
||||
|
||||
|
@ -707,7 +708,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
}
|
||||
|
||||
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
|
||||
InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
|
||||
InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
@ -788,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
_currentHeapAddr,
|
||||
pagesCount,
|
||||
pageList,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryOperation.MapVa);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -798,7 +799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return result;
|
||||
}
|
||||
|
||||
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
|
||||
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -816,8 +817,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
sizeDelta,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Heap,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -886,13 +887,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.AttributeChangeAllowed,
|
||||
MemoryState.AttributeChangeAllowed,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.BorrowedAndIpcMapped,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.DeviceMappedAndUncached,
|
||||
out MemoryState state,
|
||||
out MemoryPermission permission,
|
||||
out KMemoryPermission permission,
|
||||
out MemoryAttribute attribute))
|
||||
{
|
||||
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
|
||||
|
@ -932,9 +933,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
AddrSpaceEnd,
|
||||
~AddrSpaceEnd + 1,
|
||||
MemoryState.Reserved,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
@ -951,8 +952,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.MapAllowed,
|
||||
MemoryState.MapAllowed,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -975,18 +976,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
AddVaRangeToPageList(pageList, src, pagesCount);
|
||||
|
||||
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
|
||||
KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite);
|
||||
result = MapPages(dst, pageList, KMemoryPermission.ReadAndWrite);
|
||||
|
||||
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.");
|
||||
}
|
||||
|
@ -994,8 +995,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return result;
|
||||
}
|
||||
|
||||
InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed);
|
||||
InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite);
|
||||
InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
|
||||
InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
@ -1017,8 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
stateExpected,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -1058,8 +1059,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.MapAllowed,
|
||||
MemoryState.MapAllowed,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.Borrowed,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -1072,13 +1073,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Stack,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out _,
|
||||
out MemoryPermission dstPermission,
|
||||
out KMemoryPermission dstPermission,
|
||||
out _);
|
||||
|
||||
if (success)
|
||||
|
@ -1108,7 +1109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return result;
|
||||
}
|
||||
|
||||
result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite);
|
||||
result = MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -1117,7 +1118,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return result;
|
||||
}
|
||||
|
||||
InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite);
|
||||
InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
|
||||
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -1138,20 +1139,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.ProcessPermissionChangeAllowed,
|
||||
MemoryState.ProcessPermissionChangeAllowed,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out MemoryState oldState,
|
||||
out MemoryPermission oldPermission,
|
||||
out KMemoryPermission oldPermission,
|
||||
out _))
|
||||
{
|
||||
MemoryState newState = oldState;
|
||||
|
||||
// If writing into the code region is allowed, then we need
|
||||
// to change it to mutable.
|
||||
if ((permission & MemoryPermission.Write) != 0)
|
||||
if ((permission & KMemoryPermission.Write) != 0)
|
||||
{
|
||||
if (oldState == MemoryState.CodeStatic)
|
||||
{
|
||||
|
@ -1176,7 +1177,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
ulong pagesCount = size / PageSize;
|
||||
|
||||
MemoryOperation operation = (permission & MemoryPermission.Execute) != 0
|
||||
MemoryOperation operation = (permission & KMemoryPermission.Execute) != 0
|
||||
? MemoryOperation.ChangePermsAndAttributes
|
||||
: MemoryOperation.ChangePermRw;
|
||||
|
||||
|
@ -1270,10 +1271,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
address,
|
||||
pagesCount,
|
||||
MemoryState.Unmapped,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.None,
|
||||
MemoryState.Heap,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.None);
|
||||
}
|
||||
|
||||
|
@ -1410,7 +1411,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
pagesCount,
|
||||
srcPa,
|
||||
true,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryOperation.MapPa);
|
||||
|
||||
dstVa += pagesCount * PageSize;
|
||||
|
@ -1428,7 +1429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong src,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected)
|
||||
{
|
||||
|
@ -1450,7 +1451,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong size,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected,
|
||||
ulong src)
|
||||
|
@ -1474,7 +1475,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong serverAddress,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected,
|
||||
bool toServer)
|
||||
|
@ -1529,7 +1530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong size,
|
||||
ulong src,
|
||||
KMemoryManager sourceMemMgr,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryState state,
|
||||
bool copyData,
|
||||
out ulong dst)
|
||||
|
@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
private KernelResult GetPagesForMappingIntoAnotherProcess(
|
||||
ulong address,
|
||||
ulong size,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryState state,
|
||||
bool copyData,
|
||||
bool aslrDisabled,
|
||||
|
@ -1600,9 +1601,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
default: return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
MemoryPermission permissionMask = permission == MemoryPermission.ReadAndWrite
|
||||
? MemoryPermission.None
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permissionMask = permission == KMemoryPermission.ReadAndWrite
|
||||
? KMemoryPermission.None
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
|
||||
|
||||
|
@ -1634,7 +1635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
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 blockSize = GetSizeInRange(info, addressRounded, endAddrVisited);
|
||||
|
@ -1661,7 +1662,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
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.
|
||||
if ((info.State & stateMask) != stateMask ||
|
||||
|
@ -1678,7 +1679,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
ulong blockPagesCount = blockSize / PageSize;
|
||||
|
||||
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
|
||||
if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
|
||||
{
|
||||
result = DoMmuOperation(
|
||||
blockAddress,
|
||||
|
@ -1784,7 +1785,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
ulong unusedSizeBefore = address - addressTruncated;
|
||||
|
||||
_context.Memory.ZeroFill(dstFirstPagePa, unusedSizeBefore);
|
||||
_context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore);
|
||||
|
||||
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
|
||||
|
||||
|
@ -1803,7 +1804,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
if (unusedSizeAfter != 0)
|
||||
{
|
||||
_context.Memory.ZeroFill(firstPageFillAddress, unusedSizeAfter);
|
||||
_context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter);
|
||||
}
|
||||
|
||||
if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success)
|
||||
|
@ -1865,7 +1866,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
unusedSizeAfter = PageSize;
|
||||
}
|
||||
|
||||
_context.Memory.ZeroFill(lastPageFillAddr, unusedSizeAfter);
|
||||
_context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter);
|
||||
|
||||
if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success)
|
||||
{
|
||||
|
@ -1897,7 +1898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
private KernelResult MapPagesFromAnotherProcess(
|
||||
ulong size,
|
||||
ulong address,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryState state,
|
||||
KPageList pageList,
|
||||
out ulong dst)
|
||||
|
@ -1975,8 +1976,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
state,
|
||||
MemoryPermission.Read,
|
||||
MemoryPermission.Read,
|
||||
KMemoryPermission.Read,
|
||||
KMemoryPermission.Read,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -1996,14 +1997,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
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.
|
||||
// Real kernel has page ref counting, so this is done as part of the unmap operation.
|
||||
if (addressTruncated != addressRounded)
|
||||
|
@ -2016,6 +2009,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated));
|
||||
}
|
||||
|
||||
KernelResult result = DoMmuOperation(
|
||||
addressTruncated,
|
||||
pagesCount,
|
||||
0,
|
||||
false,
|
||||
KMemoryPermission.None,
|
||||
MemoryOperation.Unmap);
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
|
||||
|
@ -2037,7 +2038,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong addressRounded = BitUtils.AlignUp (address, 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;
|
||||
|
||||
|
@ -2111,23 +2117,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.IpcBufferAllowed,
|
||||
MemoryState.IpcBufferAllowed,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
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(
|
||||
address,
|
||||
size,
|
||||
MemoryState.TransferMemoryAllowed,
|
||||
MemoryState.TransferMemoryAllowed,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
permission,
|
||||
|
@ -2140,11 +2146,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong size,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permissionMask,
|
||||
MemoryPermission permissionExpected,
|
||||
KMemoryPermission permissionMask,
|
||||
KMemoryPermission permissionExpected,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected,
|
||||
MemoryPermission newPermission,
|
||||
KMemoryPermission newPermission,
|
||||
MemoryAttribute attributeSetMask,
|
||||
KPageList pageList = null)
|
||||
{
|
||||
|
@ -2166,7 +2172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
attributeExpected,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out MemoryState oldState,
|
||||
out MemoryPermission oldPermission,
|
||||
out KMemoryPermission oldPermission,
|
||||
out MemoryAttribute oldAttribute))
|
||||
{
|
||||
ulong pagesCount = size / PageSize;
|
||||
|
@ -2181,7 +2187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return KernelResult.OutOfResource;
|
||||
}
|
||||
|
||||
if (newPermission == MemoryPermission.None)
|
||||
if (newPermission == KMemoryPermission.None)
|
||||
{
|
||||
newPermission = oldPermission;
|
||||
}
|
||||
|
@ -2222,11 +2228,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.IpcBufferAllowed,
|
||||
MemoryState.IpcBufferAllowed,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.Borrowed,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Borrowed);
|
||||
}
|
||||
|
||||
|
@ -2237,11 +2243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.TransferMemoryAllowed,
|
||||
MemoryState.TransferMemoryAllowed,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.Borrowed,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Borrowed,
|
||||
pageList);
|
||||
}
|
||||
|
@ -2251,11 +2257,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong size,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permissionMask,
|
||||
MemoryPermission permissionExpected,
|
||||
KMemoryPermission permissionMask,
|
||||
KMemoryPermission permissionExpected,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected,
|
||||
MemoryPermission newPermission,
|
||||
KMemoryPermission newPermission,
|
||||
MemoryAttribute attributeClearMask,
|
||||
KPageList pageList = null)
|
||||
{
|
||||
|
@ -2277,7 +2283,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
attributeExpected,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out MemoryState oldState,
|
||||
out MemoryPermission oldPermission,
|
||||
out KMemoryPermission oldPermission,
|
||||
out MemoryAttribute oldAttribute))
|
||||
{
|
||||
ulong pagesCount = size / PageSize;
|
||||
|
@ -2299,7 +2305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return KernelResult.OutOfResource;
|
||||
}
|
||||
|
||||
if (newPermission == MemoryPermission.None)
|
||||
if (newPermission == KMemoryPermission.None)
|
||||
{
|
||||
newPermission = oldPermission;
|
||||
}
|
||||
|
@ -2385,8 +2391,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Unmapped,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.Mask,
|
||||
KMemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
|
@ -2400,13 +2406,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong size,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permissionMask,
|
||||
MemoryPermission permissionExpected,
|
||||
KMemoryPermission permissionMask,
|
||||
KMemoryPermission permissionExpected,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected,
|
||||
MemoryAttribute attributeIgnoreMask,
|
||||
out MemoryState outState,
|
||||
out MemoryPermission outPermission,
|
||||
out KMemoryPermission outPermission,
|
||||
out MemoryAttribute outAttribute)
|
||||
{
|
||||
ulong endAddr = address + size;
|
||||
|
@ -2416,7 +2422,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
KMemoryInfo info = node.Value.GetInfo();
|
||||
|
||||
MemoryState firstState = info.State;
|
||||
MemoryPermission firstPermission = info.Permission;
|
||||
KMemoryPermission firstPermission = info.Permission;
|
||||
MemoryAttribute firstAttribute = info.Attribute;
|
||||
|
||||
do
|
||||
|
@ -2432,7 +2438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
(firstPermission & permissionMask) != permissionExpected)
|
||||
{
|
||||
outState = MemoryState.Unmapped;
|
||||
outPermission = MemoryPermission.None;
|
||||
outPermission = KMemoryPermission.None;
|
||||
outAttribute = MemoryAttribute.None;
|
||||
|
||||
return false;
|
||||
|
@ -2452,8 +2458,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong size,
|
||||
MemoryState stateMask,
|
||||
MemoryState stateExpected,
|
||||
MemoryPermission permissionMask,
|
||||
MemoryPermission permissionExpected,
|
||||
KMemoryPermission permissionMask,
|
||||
KMemoryPermission permissionExpected,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeExpected)
|
||||
{
|
||||
|
@ -2490,10 +2496,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong baseAddress,
|
||||
ulong pagesCount,
|
||||
MemoryState oldState,
|
||||
MemoryPermission oldPermission,
|
||||
KMemoryPermission oldPermission,
|
||||
MemoryAttribute oldAttribute,
|
||||
MemoryState newState,
|
||||
MemoryPermission newPermission,
|
||||
KMemoryPermission newPermission,
|
||||
MemoryAttribute newAttribute)
|
||||
{
|
||||
// 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;
|
||||
|
||||
ValidateInternalState();
|
||||
}
|
||||
|
||||
private void InsertBlock(
|
||||
ulong baseAddress,
|
||||
ulong pagesCount,
|
||||
MemoryState state,
|
||||
MemoryPermission permission = MemoryPermission.None,
|
||||
KMemoryPermission permission = KMemoryPermission.None,
|
||||
MemoryAttribute attribute = MemoryAttribute.None)
|
||||
{
|
||||
// Inserts new block at the list, replacing and splitting
|
||||
|
@ -2605,25 +2613,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
}
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
private static void RestoreIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
|
||||
private static void RestoreIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
|
||||
{
|
||||
block.RestoreIpcMappingPermission();
|
||||
}
|
||||
|
||||
private delegate void BlockMutator(KMemoryBlock block, MemoryPermission newPerm);
|
||||
private delegate void BlockMutator(KMemoryBlock block, KMemoryPermission newPerm);
|
||||
|
||||
private void InsertBlock(
|
||||
ulong baseAddress,
|
||||
ulong pagesCount,
|
||||
BlockMutator blockMutate,
|
||||
MemoryPermission permission = MemoryPermission.None)
|
||||
KMemoryPermission permission = KMemoryPermission.None)
|
||||
{
|
||||
// Inserts new block at the list, replacing and splitting
|
||||
// existing blocks as needed, then calling the callback
|
||||
|
@ -2671,6 +2681,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
}
|
||||
|
||||
_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)
|
||||
|
@ -2876,13 +2911,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
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 regionBaseAddr = GetBaseAddrForState(state);
|
||||
|
||||
ulong regionEndAddr = regionBaseAddr + GetSizeForState(state);
|
||||
ulong regionBaseAddr = GetBaseAddress(state);
|
||||
ulong regionEndAddr = regionBaseAddr + GetSize(state);
|
||||
|
||||
bool InsideRegion()
|
||||
{
|
||||
|
@ -2891,17 +2925,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
endAddr - 1 <= regionEndAddr - 1;
|
||||
}
|
||||
|
||||
bool OutsideHeapRegion()
|
||||
{
|
||||
return endAddr <= HeapRegionStart ||
|
||||
address >= HeapRegionEnd;
|
||||
}
|
||||
|
||||
bool OutsideMapRegion()
|
||||
{
|
||||
return endAddr <= AliasRegionStart ||
|
||||
address >= AliasRegionEnd;
|
||||
}
|
||||
bool OutsideHeapRegion() => endAddr <= HeapRegionStart || address >= HeapRegionEnd;
|
||||
bool OutsideAliasRegion() => endAddr <= AliasRegionStart || address >= AliasRegionEnd;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
|
@ -2919,10 +2944,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
case MemoryState.ProcessMemory:
|
||||
case MemoryState.CodeReadOnly:
|
||||
case MemoryState.CodeWritable:
|
||||
return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion();
|
||||
return InsideRegion() && OutsideHeapRegion() && OutsideAliasRegion();
|
||||
|
||||
case MemoryState.Heap:
|
||||
return InsideRegion() && OutsideMapRegion();
|
||||
return InsideRegion() && OutsideAliasRegion();
|
||||
|
||||
case MemoryState.IpcBuffer0:
|
||||
case MemoryState.IpcBuffer1:
|
||||
|
@ -2936,7 +2961,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
throw new ArgumentException($"Invalid state value \"{state}\".");
|
||||
}
|
||||
|
||||
private ulong GetBaseAddrForState(MemoryState state)
|
||||
private ulong GetBaseAddress(MemoryState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
|
@ -2975,7 +3000,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
throw new ArgumentException($"Invalid state value \"{state}\".");
|
||||
}
|
||||
|
||||
private ulong GetSizeForState(MemoryState state)
|
||||
private ulong GetSize(MemoryState 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;
|
||||
|
||||
|
@ -3090,11 +3115,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
pagesCount,
|
||||
0,
|
||||
false,
|
||||
MemoryPermission.None,
|
||||
KMemoryPermission.None,
|
||||
MemoryOperation.Unmap);
|
||||
}
|
||||
|
||||
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission)
|
||||
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, KMemoryPermission permission)
|
||||
{
|
||||
return DoMmuOperation(
|
||||
address,
|
||||
|
@ -3110,7 +3135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong pagesCount,
|
||||
ulong srcPa,
|
||||
bool map,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryOperation operation)
|
||||
{
|
||||
if (map != (operation == MemoryOperation.MapPa))
|
||||
|
@ -3171,7 +3196,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
ulong pagesCount,
|
||||
KPageList pageList,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryOperation operation)
|
||||
{
|
||||
if (operation != MemoryOperation.MapVa)
|
||||
|
|
|
@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
private readonly long _ownerPid;
|
||||
|
||||
private readonly MemoryPermission _ownerPermission;
|
||||
private readonly MemoryPermission _userPermission;
|
||||
private readonly KMemoryPermission _ownerPermission;
|
||||
private readonly KMemoryPermission _userPermission;
|
||||
|
||||
public KSharedMemory(
|
||||
KernelContext context,
|
||||
KPageList pageList,
|
||||
long ownerPid,
|
||||
MemoryPermission ownerPermission,
|
||||
MemoryPermission userPermission) : base(context)
|
||||
KMemoryPermission ownerPermission,
|
||||
KMemoryPermission userPermission) : base(context)
|
||||
{
|
||||
_pageList = pageList;
|
||||
_ownerPid = ownerPid;
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
ulong size,
|
||||
KProcess process,
|
||||
MemoryPermission permission)
|
||||
KMemoryPermission permission)
|
||||
{
|
||||
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
MemoryPermission expectedPermission = process.Pid == _ownerPid
|
||||
KMemoryPermission expectedPermission = process.Pid == _ownerPid
|
||||
? _ownerPermission
|
||||
: _userPermission;
|
||||
|
||||
|
|
|
@ -8,12 +8,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
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;
|
||||
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize;
|
||||
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
public KMemoryPermission Permission { get; private set; }
|
||||
|
||||
private bool _hasBeenInitialized;
|
||||
private bool _isMapped;
|
||||
|
@ -23,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
_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();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
|||
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
{
|
||||
[Flags]
|
||||
enum MemoryPermission : byte
|
||||
enum KMemoryPermission : byte
|
||||
{
|
||||
None = 0,
|
||||
Mask = 0xff,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.Loaders.Elf;
|
||||
using Ryujinx.Memory;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
break;
|
||||
}
|
||||
|
||||
if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute)
|
||||
if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute)
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -335,7 +335,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
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);
|
||||
|
||||
|
|
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.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
class KProcess : KSynchronizationObject
|
||||
{
|
||||
public const int KernelVersionMajor = 10;
|
||||
public const int KernelVersionMinor = 4;
|
||||
public const int KernelVersionMajor = 10;
|
||||
public const int KernelVersionMinor = 4;
|
||||
public const int KernelVersionRevision = 0;
|
||||
|
||||
public const int KernelVersionPacked =
|
||||
(KernelVersionMajor << 19) |
|
||||
(KernelVersionMinor << 15) |
|
||||
(KernelVersionMajor << 19) |
|
||||
(KernelVersionMinor << 15) |
|
||||
(KernelVersionRevision << 0);
|
||||
|
||||
public KMemoryManager MemoryManager { get; private set; }
|
||||
|
@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
public long[] RandomEntropy { get; private set; }
|
||||
|
||||
private bool _signaled;
|
||||
private bool _useSystemMemBlocks;
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
private int _threadCount;
|
||||
|
||||
public int MmuFlags { get; private set; }
|
||||
public ProcessCreationFlags Flags { get; private set; }
|
||||
|
||||
private MemoryRegion _memRegion;
|
||||
|
||||
public KProcessCapabilities Capabilities { 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 ThreadStart _customThreadStart;
|
||||
private ulong _imageSize;
|
||||
private ulong _mainThreadStackSize;
|
||||
private ulong _memoryUsageCapacity;
|
||||
private int _version;
|
||||
private int _version;
|
||||
|
||||
public KHandleTable HandleTable { get; private set; }
|
||||
|
||||
|
@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public bool IsPaused { get; private set; }
|
||||
|
||||
public MemoryManager CpuMemory { get; private set; }
|
||||
public CpuContext CpuContext { get; private set; }
|
||||
private IProcessContextFactory _contextFactory;
|
||||
public IProcessContext Context { get; private set; }
|
||||
public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
|
||||
|
||||
public HleProcessDebugger Debugger { get; private set; }
|
||||
|
||||
public KProcess(KernelContext context) : base(context)
|
||||
{
|
||||
_processLock = new object();
|
||||
_processLock = new object();
|
||||
_threadingLock = new object();
|
||||
|
||||
AddressArbiter = new KAddressArbiter(context);
|
||||
|
@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
||||
|
||||
// TODO: Remove once we no longer need to initialize it externally.
|
||||
HandleTable = new KHandleTable(context);
|
||||
|
||||
_threads = new LinkedList<KThread>();
|
||||
|
||||
Debugger = new HleProcessDebugger(this);
|
||||
|
@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public KernelResult InitializeKip(
|
||||
ProcessCreationInfo creationInfo,
|
||||
int[] caps,
|
||||
KPageList pageList,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion)
|
||||
ReadOnlySpan<int> capabilities,
|
||||
KPageList pageList,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion,
|
||||
IProcessContextFactory contextFactory)
|
||||
{
|
||||
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 codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||
|
||||
KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0
|
||||
KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
|
||||
? KernelContext.LargeMemoryBlockAllocator
|
||||
: KernelContext.SmallMemoryBlockAllocator;
|
||||
|
||||
|
@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
|
||||
if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
|
||||
{
|
||||
return KernelResult.InvalidMemRange;
|
||||
}
|
||||
|
@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
codeAddress,
|
||||
pageList,
|
||||
MemoryState.CodeStatic,
|
||||
MemoryPermission.None);
|
||||
KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForKernel(caps, MemoryManager);
|
||||
result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public KernelResult Initialize(
|
||||
ProcessCreationInfo creationInfo,
|
||||
int[] caps,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion)
|
||||
ReadOnlySpan<int> capabilities,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion,
|
||||
IProcessContextFactory contextFactory,
|
||||
ThreadStart customThreadStart = null)
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
}
|
||||
|
||||
PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount;
|
||||
PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount;
|
||||
|
||||
KMemoryBlockAllocator memoryBlockAllocator;
|
||||
|
||||
|
@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
else
|
||||
{
|
||||
memoryBlockAllocator = (MmuFlags & 0x40) != 0
|
||||
memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
|
||||
? KernelContext.LargeMemoryBlockAllocator
|
||||
: 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;
|
||||
|
||||
|
@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
|
||||
if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
|
||||
{
|
||||
CleanUpForError();
|
||||
|
||||
|
@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
codeAddress,
|
||||
codePagesCount,
|
||||
MemoryState.CodeStatic,
|
||||
MemoryPermission.None);
|
||||
KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForUser(caps, MemoryManager);
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
CleanUpForError();
|
||||
}
|
||||
|
||||
_customThreadStart = customThreadStart;
|
||||
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
|
||||
if (KernelContext.EnableVersionChecks)
|
||||
|
@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
MmuFlags = creationInfo.MmuFlags;
|
||||
_version = creationInfo.Version;
|
||||
TitleId = creationInfo.TitleId;
|
||||
Flags = creationInfo.Flags;
|
||||
_version = creationInfo.Version;
|
||||
TitleId = creationInfo.TitleId;
|
||||
_entrypoint = creationInfo.CodeAddress;
|
||||
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||
|
||||
_useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0;
|
||||
|
||||
switch ((AddressSpaceType)((MmuFlags >> 1) & 7))
|
||||
switch (Flags & ProcessCreationFlags.AddressSpaceMask)
|
||||
{
|
||||
case AddressSpaceType.Addr32Bits:
|
||||
case AddressSpaceType.Addr36Bits:
|
||||
case AddressSpaceType.Addr39Bits:
|
||||
case ProcessCreationFlags.AddressSpace32Bit:
|
||||
case ProcessCreationFlags.AddressSpace64BitDeprecated:
|
||||
case ProcessCreationFlags.AddressSpace64Bit:
|
||||
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
||||
MemoryManager.HeapRegionStart;
|
||||
break;
|
||||
|
||||
case AddressSpaceType.Addr32BitsNoMap:
|
||||
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
|
||||
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
||||
MemoryManager.HeapRegionStart +
|
||||
MemoryManager.AliasRegionEnd -
|
||||
MemoryManager.AliasRegionStart;
|
||||
break;
|
||||
|
||||
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}.");
|
||||
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
|
||||
}
|
||||
|
||||
GenerateRandomEntropy();
|
||||
|
@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
|
||||
ulong regionStart = MemoryManager.TlsIoRegionStart;
|
||||
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
|
||||
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
|
||||
|
||||
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
||||
|
||||
|
@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
regionStart,
|
||||
regionPagesCount,
|
||||
MemoryState.ThreadLocal,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
out ulong tlsPageVa);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
KernelResult result = KernelResult.Success;
|
||||
|
||||
KTlsPageInfo pageInfo = null;
|
||||
KTlsPageInfo 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
|
||||
// memory usage capacity of this Process. Also check for possible overflow
|
||||
// on the above addition.
|
||||
if (neededSize > _memoryUsageCapacity ||
|
||||
neededSize < stackSizeRounded)
|
||||
if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
|
||||
{
|
||||
threadResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||
|
||||
|
@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;
|
||||
|
||||
ulong regionStart = MemoryManager.StackRegionStart;
|
||||
ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
|
||||
ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
|
||||
|
||||
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
||||
|
||||
|
@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
regionStart,
|
||||
regionPagesCount,
|
||||
MemoryState.Stack,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
out ulong stackBottom);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
stackTop,
|
||||
mainThreadPriority,
|
||||
DefaultCpuCore,
|
||||
this);
|
||||
this,
|
||||
ThreadType.User,
|
||||
_customThreadStart);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
SetState(newState);
|
||||
|
||||
// TODO: We can't call KThread.Start from a non-guest thread.
|
||||
// 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();
|
||||
result = mainThread.Start();
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
SetState(OldState);
|
||||
SetState(oldState);
|
||||
|
||||
CleanUpForError();
|
||||
} */
|
||||
|
||||
mainThread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
|
@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
if (State != newState)
|
||||
{
|
||||
State = newState;
|
||||
State = newState;
|
||||
_signaled = true;
|
||||
|
||||
Signal();
|
||||
|
@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public KernelResult InitializeThread(
|
||||
KThread thread,
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int cpuCore)
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int cpuCore)
|
||||
{
|
||||
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)
|
||||
{
|
||||
context.Interrupt += InterruptHandler;
|
||||
context.Interrupt += InterruptHandler;
|
||||
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
|
||||
context.Undefined += UndefinedInstructionHandler;
|
||||
context.Undefined += UndefinedInstructionHandler;
|
||||
}
|
||||
|
||||
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 ||
|
||||
State == ProcessState.Crashed ||
|
||||
if (State == ProcessState.Started ||
|
||||
State == ProcessState.Crashed ||
|
||||
State == ProcessState.Attached ||
|
||||
State == ProcessState.DebugSuspended)
|
||||
{
|
||||
|
@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
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,
|
||||
AddressSpaceType.Addr36Bits => 36,
|
||||
AddressSpaceType.Addr32BitsNoMap => 32,
|
||||
AddressSpaceType.Addr39Bits => 39,
|
||||
_ => throw new ArgumentException(nameof(addrSpaceType))
|
||||
ProcessCreationFlags.AddressSpace32Bit => 32,
|
||||
ProcessCreationFlags.AddressSpace64BitDeprecated => 36,
|
||||
ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32,
|
||||
ProcessCreationFlags.AddressSpace64Bit => 39,
|
||||
_ => 39
|
||||
};
|
||||
|
||||
CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
|
||||
CpuContext = new CpuContext(CpuMemory);
|
||||
Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
|
||||
|
||||
// TODO: This should eventually be removed.
|
||||
// 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);
|
||||
}
|
||||
|
@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
throw new UndefinedInstructionException(e.Address, e.OpCode);
|
||||
}
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
CpuMemory.Dispose();
|
||||
}
|
||||
protected override void Destroy() => Context.Dispose();
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ using Ryujinx.Common;
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
|
@ -24,29 +25,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
IrqAccessMask = new byte[0x80];
|
||||
}
|
||||
|
||||
public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager)
|
||||
public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||
{
|
||||
AllowedCpuCoresMask = 0xf;
|
||||
AllowedThreadPriosMask = -1;
|
||||
DebuggingFlags &= ~3;
|
||||
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 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)
|
||||
{
|
||||
|
@ -59,14 +60,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((uint)index + 1 >= caps.Length)
|
||||
if ((uint)index + 1 >= capabilities.Length)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
int prevCap = cap;
|
||||
|
||||
cap = caps[++index];
|
||||
cap = capabilities[++index];
|
||||
|
||||
if (((cap + 1) & ~cap) != 0x40)
|
||||
{
|
||||
|
@ -91,9 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
MemoryPermission perm = (prevCap >> 31) != 0
|
||||
? MemoryPermission.Read
|
||||
: MemoryPermission.ReadAndWrite;
|
||||
KMemoryPermission perm = (prevCap >> 31) != 0
|
||||
? KMemoryPermission.Read
|
||||
: KMemoryPermission.ReadAndWrite;
|
||||
|
||||
KernelResult result;
|
||||
|
||||
|
@ -216,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
long address = ((long)(uint)cap << 4) & 0xffffff000;
|
||||
|
||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, KMemoryPermission.ReadAndWrite);
|
||||
|
||||
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
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public string Name { get; }
|
||||
|
||||
public int Version { get; private set; }
|
||||
public ulong TitleId { get; private set; }
|
||||
public int Version { get; }
|
||||
public ulong TitleId { get; }
|
||||
|
||||
public ulong CodeAddress { get; private set; }
|
||||
public int CodePagesCount { get; private set; }
|
||||
public ulong CodeAddress { get; }
|
||||
public int CodePagesCount { get; }
|
||||
|
||||
public int MmuFlags { get; private set; }
|
||||
public int ResourceLimitHandle { get; private set; }
|
||||
public int PersonalMmHeapPagesCount { get; private set; }
|
||||
public ProcessCreationFlags Flags { get; }
|
||||
public int ResourceLimitHandle { get; }
|
||||
public int SystemResourcePagesCount { get; }
|
||||
|
||||
public ProcessCreationInfo(
|
||||
string name,
|
||||
int category,
|
||||
ulong titleId,
|
||||
ulong codeAddress,
|
||||
int codePagesCount,
|
||||
int mmuFlags,
|
||||
int resourceLimitHandle,
|
||||
int personalMmHeapPagesCount)
|
||||
int version,
|
||||
ulong titleId,
|
||||
ulong codeAddress,
|
||||
int codePagesCount,
|
||||
ProcessCreationFlags flags,
|
||||
int resourceLimitHandle,
|
||||
int systemResourcePagesCount)
|
||||
{
|
||||
Name = name;
|
||||
Version = category;
|
||||
TitleId = titleId;
|
||||
CodeAddress = codeAddress;
|
||||
CodePagesCount = codePagesCount;
|
||||
MmuFlags = mmuFlags;
|
||||
ResourceLimitHandle = resourceLimitHandle;
|
||||
PersonalMmHeapPagesCount = personalMmHeapPagesCount;
|
||||
Name = name;
|
||||
Version = version;
|
||||
TitleId = titleId;
|
||||
CodeAddress = codeAddress;
|
||||
CodePagesCount = codePagesCount;
|
||||
Flags = flags;
|
||||
ResourceLimitHandle = resourceLimitHandle;
|
||||
SystemResourcePagesCount = systemResourcePagesCount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,21 +7,167 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
|
|||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
class Syscall
|
||||
{
|
||||
private readonly Switch _device;
|
||||
private readonly KernelContext _context;
|
||||
|
||||
public Syscall(Switch device, KernelContext context)
|
||||
public Syscall(KernelContext context)
|
||||
{
|
||||
_device = device;
|
||||
_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
|
||||
|
||||
public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
|
||||
|
@ -33,6 +179,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
return ConnectToNamedPort(name, out handle);
|
||||
}
|
||||
|
||||
public KernelResult ConnectToNamedPort(string name, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (name.Length > 11)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
|
@ -70,61 +223,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestHLE(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)
|
||||
public KernelResult SendSyncRequest(int handle)
|
||||
{
|
||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
|
@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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]);
|
||||
|
||||
|
@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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;
|
||||
}
|
||||
|
@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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))
|
||||
{
|
||||
|
@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
|
||||
if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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;
|
||||
|
||||
|
@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
|
||||
if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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))
|
||||
{
|
||||
|
@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
if (permission != MemoryPermission.None &&
|
||||
permission != MemoryPermission.Read &&
|
||||
permission != MemoryPermission.ReadAndWrite &&
|
||||
permission != MemoryPermission.ReadAndExecute)
|
||||
if (permission != KMemoryPermission.None &&
|
||||
permission != KMemoryPermission.Read &&
|
||||
permission != KMemoryPermission.ReadAndWrite &&
|
||||
permission != KMemoryPermission.ReadAndExecute)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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)
|
||||
{
|
||||
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
||||
|
@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidThread;
|
||||
}
|
||||
|
||||
MemoryManager memory = currentProcess.CpuMemory;
|
||||
IVirtualMemoryManager memory = currentProcess.CpuMemory;
|
||||
|
||||
memory.Write(address + 0x0, thread.Context.GetX(0));
|
||||
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)
|
||||
{
|
||||
return _syscall.SendSyncRequestHLE(handle);
|
||||
return _syscall.SendSyncRequest(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(
|
||||
|
@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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);
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
public KernelResult CreateTransferMemory32(
|
||||
[R(1)] uint address,
|
||||
[R(2)] uint size,
|
||||
[R(3)] MemoryPermission permission,
|
||||
[R(3)] KMemoryPermission permission,
|
||||
[R(1)] out int handle)
|
||||
{
|
||||
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
[R(2)] uint srcLow,
|
||||
[R(3)] uint srcHigh,
|
||||
[R(4)] uint sizeHigh,
|
||||
[R(5)] MemoryPermission permission)
|
||||
[R(5)] KMemoryPermission permission)
|
||||
{
|
||||
ulong src = srcLow | ((ulong)srcHigh << 32);
|
||||
ulong size = sizeLow | ((ulong)sizeHigh << 32);
|
||||
|
|
|
@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
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)
|
||||
{
|
||||
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
|
||||
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
||||
}
|
||||
|
||||
public KernelResult SendAsyncRequestWithUserBuffer64(
|
||||
|
@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
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);
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
public KernelResult CreateTransferMemory64(
|
||||
[R(1)] ulong address,
|
||||
[R(2)] ulong size,
|
||||
[R(3)] MemoryPermission permission,
|
||||
[R(3)] KMemoryPermission permission,
|
||||
[R(1)] out int 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -229,6 +229,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
KProcess dummyProcess = new KProcess(_context);
|
||||
|
||||
dummyProcess.HandleTable.Initialize(1024);
|
||||
|
||||
KThread dummyThread = new KThread(_context);
|
||||
|
||||
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; }
|
||||
|
||||
private ulong _entrypoint;
|
||||
private ThreadStart _customThreadStart;
|
||||
|
||||
public ulong MutexAddress { get; set; }
|
||||
|
||||
|
@ -48,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
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> ProcessListNode { get; set; }
|
||||
|
||||
private LinkedList<KThread> _mutexWaiters;
|
||||
private LinkedList<KThread> _mutexWaiters;
|
||||
private LinkedListNode<KThread> _mutexWaiterNode;
|
||||
|
||||
public KThread MutexOwner { get; private set; }
|
||||
|
@ -65,24 +66,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
public KernelResult ObjSyncResult { get; set; }
|
||||
|
||||
public int DynamicPriority { get; set; }
|
||||
public int CurrentCore { get; set; }
|
||||
public int BasePriority { get; set; }
|
||||
public int PreferredCore { get; set; }
|
||||
public int CurrentCore { get; set; }
|
||||
public int BasePriority { get; set; }
|
||||
public int PreferredCore { get; set; }
|
||||
|
||||
private long _affinityMaskOverride;
|
||||
private int _preferredCoreOverride;
|
||||
private int _preferredCoreOverride;
|
||||
#pragma warning disable CS0649
|
||||
private int _affinityOverrideCount;
|
||||
private int _affinityOverrideCount;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public ThreadSchedState SchedFlags { get; private set; }
|
||||
|
||||
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 WaitingSync { get; set; }
|
||||
public bool WaitingSync { get; set; }
|
||||
|
||||
private bool _hasExited;
|
||||
private bool _hasBeenInitialized;
|
||||
|
@ -98,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public KThread(KernelContext context) : base(context)
|
||||
{
|
||||
_scheduler = KernelContext.Scheduler;
|
||||
_scheduler = KernelContext.Scheduler;
|
||||
_schedulingData = KernelContext.Scheduler.SchedulingData;
|
||||
|
||||
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
|
||||
|
@ -110,14 +115,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
|
||||
public KernelResult Initialize(
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int defaultCpuCore,
|
||||
KProcess owner,
|
||||
ThreadType type = ThreadType.User,
|
||||
ThreadStart customHostThreadStart = null)
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int defaultCpuCore,
|
||||
KProcess owner,
|
||||
ThreadType type,
|
||||
ThreadStart customThreadStart = null)
|
||||
{
|
||||
if ((uint)type > 3)
|
||||
{
|
||||
|
@ -135,11 +140,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
CurrentCore = PreferredCore;
|
||||
|
||||
DynamicPriority = priority;
|
||||
BasePriority = priority;
|
||||
BasePriority = priority;
|
||||
|
||||
ObjSyncResult = KernelResult.ThreadNotStarted;
|
||||
|
||||
_entrypoint = entrypoint;
|
||||
_customThreadStart = customThreadStart;
|
||||
|
||||
if (type == ThreadType.User)
|
||||
{
|
||||
|
@ -162,18 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
owner.IncrementReferenceCount();
|
||||
owner.IncrementThreadCount();
|
||||
|
||||
is64Bits = (owner.MmuFlags & 1) != 0;
|
||||
is64Bits = owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
is64Bits = true;
|
||||
}
|
||||
|
||||
HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint)));
|
||||
HostThread = new Thread(ThreadStart);
|
||||
|
||||
Context = CpuContext.CreateExecutionContext();
|
||||
|
||||
bool isAarch32 = (Owner.MmuFlags & 1) == 0;
|
||||
bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||
|
||||
Context.IsAarch32 = isAarch32;
|
||||
|
||||
|
@ -189,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
|
||||
Context.CntfrqEl0 = 19200000;
|
||||
Context.Tpidr = (long)_tlsAddress;
|
||||
Context.Tpidr = (long)_tlsAddress;
|
||||
|
||||
owner.SubscribeThreadEventHandlers(Context);
|
||||
|
||||
|
@ -249,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
{
|
||||
KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
|
||||
|
||||
while (SchedFlags != ThreadSchedState.TerminationPending &&
|
||||
while (SchedFlags != ThreadSchedState.TerminationPending &&
|
||||
currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
|
||||
!currentThread.ShallBeTerminated)
|
||||
{
|
||||
|
@ -351,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
Context.RequestInterrupt();
|
||||
}
|
||||
|
||||
SignaledObj = null;
|
||||
SignaledObj = null;
|
||||
ObjSyncResult = KernelResult.ThreadTerminating;
|
||||
|
||||
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,
|
||||
// unless the priority is higher than the current one.
|
||||
if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
|
||||
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
|
||||
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
|
||||
{
|
||||
yield return thread;
|
||||
}
|
||||
|
@ -701,7 +707,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
else
|
||||
{
|
||||
SignaledObj = null;
|
||||
SignaledObj = null;
|
||||
ObjSyncResult = KernelResult.Cancelled;
|
||||
|
||||
SetNewSchedFlags(ThreadSchedState.Running);
|
||||
|
@ -734,14 +740,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
if (useOverride)
|
||||
{
|
||||
_preferredCoreOverride = newCore;
|
||||
_affinityMaskOverride = newAffinityMask;
|
||||
_affinityMaskOverride = newAffinityMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
long oldAffinityMask = AffinityMask;
|
||||
|
||||
PreferredCore = newCore;
|
||||
AffinityMask = newAffinityMask;
|
||||
AffinityMask = newAffinityMask;
|
||||
|
||||
if (oldAffinityMask != newAffinityMask)
|
||||
{
|
||||
|
@ -783,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
private void CombineForcePauseFlags()
|
||||
{
|
||||
ThreadSchedState oldFlags = SchedFlags;
|
||||
ThreadSchedState oldFlags = SchedFlags;
|
||||
ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
|
||||
|
||||
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.RemoveThread(this);
|
||||
|
||||
Context.Dispose();
|
||||
}
|
||||
|
||||
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.
|
||||
foreach (KThread thread in _mutexWaiters)
|
||||
{
|
||||
thread.MutexOwner = null;
|
||||
thread.MutexOwner = null;
|
||||
thread._preferredCoreOverride = 0;
|
||||
thread.ObjSyncResult = KernelResult.InvalidState;
|
||||
thread.ObjSyncResult = KernelResult.InvalidState;
|
||||
|
||||
thread.ReleaseAndResume();
|
||||
}
|
||||
|
|
|
@ -36,23 +36,23 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;
|
||||
|
||||
int mmuFlags = 0;
|
||||
ProcessCreationFlags flags = 0;
|
||||
|
||||
if (AslrEnabled)
|
||||
{
|
||||
// TODO: Randomization.
|
||||
|
||||
mmuFlags |= 0x20;
|
||||
flags |= ProcessCreationFlags.EnableAslr;
|
||||
}
|
||||
|
||||
if (kip.Is64BitAddressSpace)
|
||||
{
|
||||
mmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
|
||||
flags |= ProcessCreationFlags.AddressSpace64Bit;
|
||||
}
|
||||
|
||||
if (kip.Is64Bit)
|
||||
{
|
||||
mmuFlags |= 1;
|
||||
flags |= ProcessCreationFlags.Is64Bit;
|
||||
}
|
||||
|
||||
ProcessCreationInfo creationInfo = new ProcessCreationInfo(
|
||||
|
@ -61,7 +61,7 @@ namespace Ryujinx.HLE.HOS
|
|||
kip.ProgramId,
|
||||
codeAddress,
|
||||
codePagesCount,
|
||||
mmuFlags,
|
||||
flags,
|
||||
0,
|
||||
0);
|
||||
|
||||
|
@ -82,12 +82,15 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
KProcess process = new KProcess(context);
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory();
|
||||
|
||||
result = process.InitializeKip(
|
||||
creationInfo,
|
||||
kip.Capabilities,
|
||||
pageList,
|
||||
context.ResourceLimit,
|
||||
memoryRegion);
|
||||
memoryRegion,
|
||||
processContextFactory);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -183,7 +186,7 @@ namespace Ryujinx.HLE.HOS
|
|||
metaData.Aci0.TitleId,
|
||||
codeStart,
|
||||
codePagesCount,
|
||||
metaData.MmuFlags,
|
||||
(ProcessCreationFlags)metaData.ProcessFlags | ProcessCreationFlags.IsApplication,
|
||||
0,
|
||||
personalMmHeapPagesCount);
|
||||
|
||||
|
@ -217,11 +220,14 @@ namespace Ryujinx.HLE.HOS
|
|||
return false;
|
||||
}
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory();
|
||||
|
||||
result = process.Initialize(
|
||||
creationInfo,
|
||||
metaData.Aci0.KernelAccessControl.Capabilities,
|
||||
resourceLimit,
|
||||
memoryRegion);
|
||||
memoryRegion,
|
||||
processContextFactory);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -280,7 +286,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -292,21 +298,21 @@ namespace Ryujinx.HLE.HOS
|
|||
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)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, MemoryPermission.Read);
|
||||
result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
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.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Memory;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
class ServiceCtx
|
||||
{
|
||||
public Switch Device { get; }
|
||||
public KProcess Process { get; }
|
||||
public MemoryManager Memory { get; }
|
||||
public KThread Thread { get; }
|
||||
public KClientSession Session { get; }
|
||||
public IpcMessage Request { get; }
|
||||
public IpcMessage Response { get; }
|
||||
public BinaryReader RequestData { get; }
|
||||
public BinaryWriter ResponseData { get; }
|
||||
public Switch Device { get; }
|
||||
public KProcess Process { get; }
|
||||
public IVirtualMemoryManager Memory { get; }
|
||||
public KThread Thread { get; }
|
||||
public IpcMessage Request { get; }
|
||||
public IpcMessage Response { get; }
|
||||
public BinaryReader RequestData { get; }
|
||||
public BinaryWriter ResponseData { get; }
|
||||
|
||||
public ServiceCtx(
|
||||
Switch device,
|
||||
KProcess process,
|
||||
MemoryManager memory,
|
||||
KThread thread,
|
||||
KClientSession session,
|
||||
IpcMessage request,
|
||||
IpcMessage response,
|
||||
BinaryReader requestData,
|
||||
BinaryWriter responseData)
|
||||
Switch device,
|
||||
KProcess process,
|
||||
IVirtualMemoryManager memory,
|
||||
KThread thread,
|
||||
IpcMessage request,
|
||||
IpcMessage response,
|
||||
BinaryReader requestData,
|
||||
BinaryWriter responseData)
|
||||
{
|
||||
Device = device;
|
||||
Process = process;
|
||||
Memory = memory;
|
||||
Thread = thread;
|
||||
Session = session;
|
||||
Request = request;
|
||||
Response = response;
|
||||
RequestData = requestData;
|
||||
Device = device;
|
||||
Process = process;
|
||||
Memory = memory;
|
||||
Thread = thread;
|
||||
Request = request;
|
||||
Response = response;
|
||||
RequestData = requestData;
|
||||
ResponseData = responseData;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
|||
{
|
||||
class ISystemAppletProxy : IpcService
|
||||
{
|
||||
public ISystemAppletProxy() { }
|
||||
private readonly long _pid;
|
||||
|
||||
public ISystemAppletProxy(long pid)
|
||||
{
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
||||
|
@ -19,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
|||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||
public ResultCode GetSelfController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context.Device.System));
|
||||
MakeObject(context, new ISelfController(context.Device.System, _pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -28,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
|||
// GetWindowController() -> object<nn::am::service::IWindowController>
|
||||
public ResultCode GetWindowController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IWindowController());
|
||||
MakeObject(context, new IWindowController(_pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
private KEvent _normalOutDataEvent;
|
||||
private KEvent _interactiveOutDataEvent;
|
||||
|
||||
private int _stateChangedEventHandle;
|
||||
private int _normalOutDataEventHandle;
|
||||
private int _interactiveOutDataEventHandle;
|
||||
|
||||
public ILibraryAppletAccessor(AppletId appletId, Horizon system)
|
||||
{
|
||||
_stateChangedEvent = new KEvent(system.KernelContext);
|
||||
|
@ -32,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
_applet.AppletStateChanged += OnAppletStateChanged;
|
||||
_normalSession.DataAvailable += OnNormalOutData;
|
||||
_interactiveSession.DataAvailable += OnInteractiveOutData;
|
||||
|
||||
|
||||
Logger.Info?.Print(LogClass.ServiceAm, $"Applet '{appletId}' created.");
|
||||
}
|
||||
|
||||
|
@ -55,12 +59,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// GetAppletStateChangedEvent() -> handle<copy>
|
||||
public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_stateChangedEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out _stateChangedEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangedEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -69,8 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// Start()
|
||||
public ResultCode Start(ServiceCtx context)
|
||||
{
|
||||
return (ResultCode)_applet.Start(_normalSession.GetConsumer(),
|
||||
_interactiveSession.GetConsumer());
|
||||
return (ResultCode)_applet.Start(_normalSession.GetConsumer(), _interactiveSession.GetConsumer());
|
||||
}
|
||||
|
||||
[Command(30)]
|
||||
|
@ -138,12 +144,16 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// GetPopOutDataEvent() -> handle<copy>
|
||||
public ResultCode GetPopOutDataEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_normalOutDataEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out _normalOutDataEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_normalOutDataEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -152,12 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
|||
// GetPopInteractiveOutDataEvent() -> handle<copy>
|
||||
public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_interactiveOutDataEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out _interactiveOutDataEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_interactiveOutDataEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
private Apm.SystemManagerServer _apmSystemManagerServer;
|
||||
private Lbl.LblControllerServer _lblControllerServer;
|
||||
|
||||
private bool _vrModeEnabled = false;
|
||||
private bool _vrModeEnabled;
|
||||
private int _messageEventHandle;
|
||||
private int _displayResolutionChangedEventHandle;
|
||||
|
||||
public ICommonStateGetter(ServiceCtx context)
|
||||
{
|
||||
|
@ -25,14 +27,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
// GetEventHandle() -> handle<copy>
|
||||
public ResultCode GetEventHandle(ServiceCtx context)
|
||||
{
|
||||
KEvent Event = context.Device.System.AppletState.MessageEvent;
|
||||
KEvent messageEvent = context.Device.System.AppletState.MessageEvent;
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_messageEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_messageEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -147,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
_lblControllerServer.DisableVrMode();
|
||||
}
|
||||
|
||||
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
|
||||
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
|
||||
}
|
||||
|
||||
[Command(60)] // 3.0.0+
|
||||
|
@ -164,12 +169,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
// GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
|
||||
public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_displayResolutionChangedEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_displayResolutionChangedEventHandle);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
@ -189,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
|
||||
_apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode);
|
||||
|
||||
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
|
||||
// TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used.
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
class IHomeMenuFunctions : IpcService
|
||||
{
|
||||
private KEvent _channelEvent;
|
||||
private int _channelEventHandle;
|
||||
|
||||
public IHomeMenuFunctions(Horizon system)
|
||||
{
|
||||
|
@ -29,12 +30,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
// GetPopFromGeneralChannelEvent() -> handle<copy>
|
||||
public ResultCode GetPopFromGeneralChannelEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_channelEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out _channelEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_channelEventHandle);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
|
|
@ -49,7 +49,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
}
|
||||
|
||||
var data = new byte[transferMem.Size];
|
||||
context.Memory.Read(transferMem.Address, data);
|
||||
transferMem.Creator.CpuMemory.Read(transferMem.Address, data);
|
||||
|
||||
context.Device.System.KernelContext.Syscall.CloseHandle(handle);
|
||||
|
||||
MakeObject(context, new IStorage(data));
|
||||
|
||||
|
|
|
@ -8,10 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
{
|
||||
class ISelfController : IpcService
|
||||
{
|
||||
private readonly long _pid;
|
||||
|
||||
private KEvent _libraryAppletLaunchableEvent;
|
||||
private int _libraryAppletLaunchableEventHandle;
|
||||
|
||||
private KEvent _accumulatedSuspendedTickChangedEvent;
|
||||
private int _accumulatedSuspendedTickChangedEventHandle = 0;
|
||||
private int _accumulatedSuspendedTickChangedEventHandle;
|
||||
|
||||
private object _fatalSectionLock = new object();
|
||||
private int _fatalSectionCount;
|
||||
|
@ -32,9 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
private uint _screenShotImageOrientation = 0;
|
||||
private uint _idleTimeDetectionExtension = 0;
|
||||
|
||||
public ISelfController(Horizon system)
|
||||
public ISelfController(Horizon system, long pid)
|
||||
{
|
||||
_libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
|
@ -103,12 +107,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
{
|
||||
_libraryAppletLaunchableEvent.ReadableEvent.Signal();
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_libraryAppletLaunchableEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_libraryAppletLaunchableEvent.ReadableEvent, out _libraryAppletLaunchableEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_libraryAppletLaunchableEventHandle);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
@ -206,6 +213,31 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(40)]
|
||||
// CreateManagedDisplayLayer() -> u64
|
||||
public ResultCode CreateManagedDisplayLayer(ServiceCtx context)
|
||||
{
|
||||
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long layerId);
|
||||
|
||||
context.ResponseData.Write(layerId);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(44)] // 10.0.0+
|
||||
// CreateManagedDisplaySeparableLayer() -> (u64, u64)
|
||||
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
|
||||
{
|
||||
// NOTE: first create the recoding layer and then the display one because right now Surface Flinger only use the last id.
|
||||
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId);
|
||||
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long displayLayerId);
|
||||
|
||||
context.ResponseData.Write(displayLayerId);
|
||||
context.ResponseData.Write(recordingLayerId);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[Command(50)]
|
||||
// SetHandlesRequestToDisplay(b8)
|
||||
public ResultCode SetHandlesRequestToDisplay(ServiceCtx context)
|
||||
|
|
|
@ -4,7 +4,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
{
|
||||
class IWindowController : IpcService
|
||||
{
|
||||
public IWindowController() { }
|
||||
private readonly long _pid;
|
||||
|
||||
public IWindowController(long pid)
|
||||
{
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
[Command(1)]
|
||||
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
|
||||
|
@ -12,7 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
context.ResponseData.Write(0L);
|
||||
long appletResourceUserId = context.Device.System.AppletState.AppletResourceUserIds.Add(_pid);
|
||||
|
||||
context.ResponseData.Write(appletResourceUserId);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
|||
// OpenSystemAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ISystemAppletProxy>
|
||||
public ResultCode OpenSystemAppletProxy(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ISystemAppletProxy());
|
||||
MakeObject(context, new ISystemAppletProxy(context.Request.HandleDesc.PId));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||
private KEvent _friendInvitationStorageChannelEvent;
|
||||
private KEvent _notificationStorageChannelEvent;
|
||||
|
||||
private int _gpuErrorDetectedSystemEventHandle;
|
||||
private int _friendInvitationStorageChannelEventHandle;
|
||||
private int _notificationStorageChannelEventHandle;
|
||||
|
||||
public IApplicationFunctions(Horizon system)
|
||||
{
|
||||
_gpuErrorDetectedSystemEvent = new KEvent(system.KernelContext);
|
||||
|
@ -122,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
// If desired language is not supported by application, use first supported language from TitleLanguage.
|
||||
// If desired language is not supported by application, use first supported language from TitleLanguage.
|
||||
// TODO: In the future, a GUI could enable user-specified search priority
|
||||
if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
|
||||
{
|
||||
|
@ -293,12 +297,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||
resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
if (transferMemoryHandle)
|
||||
if (transferMemoryHandle != 0)
|
||||
{
|
||||
svcCloseHandle(transferMemoryHandle);
|
||||
context.Device.System.KernelContext.Syscall.CloseHandle(transferMemoryHandle);
|
||||
}
|
||||
*/
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
@ -455,15 +457,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||
// GetGpuErrorDetectedSystemEvent() -> handle<copy>
|
||||
public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out int gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
|
||||
if (_gpuErrorDetectedSystemEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(gpuErrorDetectedSystemEventHandle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_gpuErrorDetectedSystemEventHandle);
|
||||
|
||||
// NOTE: This is used by "sdk" NSO during applet-application initialization.
|
||||
// A seperate thread is setup where event-waiting is handled.
|
||||
// NOTE: This is used by "sdk" NSO during applet-application initialization.
|
||||
// A seperate thread is setup where event-waiting is handled.
|
||||
// When the Event is signaled, official sw will assert.
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -473,12 +478,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||
// GetFriendInvitationStorageChannelEvent() -> handle<copy>
|
||||
public ResultCode GetFriendInvitationStorageChannelEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out int friendInvitationStorageChannelEventHandle) != KernelResult.Success)
|
||||
if (_friendInvitationStorageChannelEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(friendInvitationStorageChannelEventHandle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_friendInvitationStorageChannelEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -501,12 +509,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||
// GetNotificationStorageChannelEvent() -> handle<copy>
|
||||
public ResultCode GetNotificationStorageChannelEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out int notificationStorageChannelEventHandle) != KernelResult.Success)
|
||||
if (_notificationStorageChannelEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(notificationStorageChannelEventHandle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationStorageChannelEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
|||
{
|
||||
class IApplicationProxy : IpcService
|
||||
{
|
||||
public IApplicationProxy() { }
|
||||
private readonly long _pid;
|
||||
|
||||
public IApplicationProxy(long pid)
|
||||
{
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
||||
|
@ -20,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
|||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||
public ResultCode GetSelfController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context.Device.System));
|
||||
MakeObject(context, new ISelfController(context.Device.System, _pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -29,7 +34,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
|||
// GetWindowController() -> object<nn::am::service::IWindowController>
|
||||
public ResultCode GetWindowController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IWindowController());
|
||||
MakeObject(context, new IWindowController(_pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
// OpenApplicationProxy(u64, pid, handle<copy>) -> object<nn::am::service::IApplicationProxy>
|
||||
public ResultCode OpenApplicationProxy(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IApplicationProxy());
|
||||
MakeObject(context, new IApplicationProxy(context.Request.HandleDesc.PId));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -10,15 +10,18 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
|
|||
{
|
||||
class IAudioOut : IpcService, IDisposable
|
||||
{
|
||||
private IAalOutput _audioOut;
|
||||
private KEvent _releaseEvent;
|
||||
private int _track;
|
||||
private readonly IAalOutput _audioOut;
|
||||
private readonly KEvent _releaseEvent;
|
||||
private int _releaseEventHandle;
|
||||
private readonly int _track;
|
||||
private readonly int _clientHandle;
|
||||
|
||||
public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track)
|
||||
public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track, int clientHandle)
|
||||
{
|
||||
_audioOut = audioOut;
|
||||
_releaseEvent = releaseEvent;
|
||||
_track = track;
|
||||
_clientHandle = clientHandle;
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
|
@ -59,12 +62,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
|
|||
// RegisterBufferEvent() -> handle<copy>
|
||||
public ResultCode RegisterBufferEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_releaseEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out _releaseEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_releaseEventHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -108,7 +114,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager
|
|||
// NOTE: Assume PCM16 all the time, change if new format are found.
|
||||
short[] buffer = new short[data.SampleBufferSize / sizeof(short)];
|
||||
|
||||
context.Memory.Read((ulong)data.SampleBufferPtr, MemoryMarshal.Cast<short, byte>(buffer));
|
||||
context.Process.HandleTable.GetKProcess(_clientHandle).CpuMemory.Read((ulong)data.SampleBufferPtr, MemoryMarshal.Cast<short, byte>(buffer));
|
||||
|
||||
_audioOut.AppendBuffer(_track, tag, buffer);
|
||||
|
||||
|
|
|
@ -33,7 +33,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
|
||||
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
|
||||
{
|
||||
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, context.Memory, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
|
||||
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
|
||||
|
||||
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
|
|
|
@ -14,9 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
|
||||
private IAudioRendererManager _impl;
|
||||
|
||||
public AudioRendererManagerServer(ServiceCtx context) : this(new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
|
||||
public AudioRendererManagerServer(ServiceCtx context) : this(context, new AudioRendererManager(context.Device.System.AudioRendererManager, context.Device.System.AudioDeviceSessionRegistry)) { }
|
||||
|
||||
public AudioRendererManagerServer(IAudioRendererManager impl) : base(new ServerBase("AudioRendererServer"))
|
||||
public AudioRendererManagerServer(ServiceCtx context, IAudioRendererManager impl) : base(new ServerBase(context.Device.System.KernelContext, "AudioRendererServer"))
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
MakeObject(context, new AudioRendererServer(renderer));
|
||||
}
|
||||
|
||||
context.Device.System.KernelContext.Syscall.CloseHandle((int)processHandle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
|
@ -57,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private uint ListAudioInsImpl(MemoryManager memory, long bufferPosition, long bufferSize, bool filtered = false)
|
||||
private uint ListAudioInsImpl(IVirtualMemoryManager memory, long bufferPosition, long bufferSize, bool filtered = false)
|
||||
{
|
||||
uint count = 0;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
private const int DefaultSampleRate = 48000;
|
||||
private const int DefaultChannelsCount = 2;
|
||||
|
||||
public IAudioOutManager(ServiceCtx context) : base(new ServerBase("AudioOutServer")) { }
|
||||
public IAudioOutManager(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "AudioOutServer")) { }
|
||||
|
||||
[Command(0)]
|
||||
// ListAudioOuts() -> (u32 count, buffer<bytes, 6>)
|
||||
|
@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
|
||||
int track = audioOut.OpenTrack(sampleRate, channels, callback);
|
||||
|
||||
MakeObject(context, new IAudioOut(audioOut, releaseEvent, track));
|
||||
MakeObject(context, new IAudioOut(audioOut, releaseEvent, track, context.Request.HandleDesc.ToCopy[0]));
|
||||
|
||||
context.ResponseData.Write(sampleRate);
|
||||
context.ResponseData.Write(channels);
|
||||
|
|
|
@ -16,6 +16,9 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||
|
||||
MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount));
|
||||
|
||||
// Close transfer memory immediately as we don't use it.
|
||||
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
|||
class IDeliveryCacheProgressService : IpcService
|
||||
{
|
||||
private KEvent _event;
|
||||
private int _eventHandle;
|
||||
|
||||
public IDeliveryCacheProgressService(ServiceCtx context)
|
||||
{
|
||||
|
@ -22,12 +23,15 @@ namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
|
|||
// GetEvent() -> handle<copy>
|
||||
public ResultCode GetEvent(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_eventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceBcat);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
}
|
||||
|
||||
[Command(8)]
|
||||
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
// -> object<nn::fssrv::sf::IFileSystem> contentFs
|
||||
public ResultCode OpenFileSystemWithId(ServiceCtx context)
|
||||
{
|
||||
|
@ -138,12 +138,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
// Workaround that by setting the application ID and owner ID if they're not already set
|
||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
||||
{
|
||||
attribute.ProgramId = new ProgramId(context.Process.TitleId);
|
||||
}
|
||||
|
||||
if (creationInfo.OwnerId == 0)
|
||||
{
|
||||
creationInfo.OwnerId = 0;
|
||||
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}");
|
||||
|
@ -215,12 +210,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
// Workaround that by setting the application ID and owner ID if they're not already set
|
||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
||||
{
|
||||
attribute.ProgramId = new ProgramId(context.Process.TitleId);
|
||||
}
|
||||
|
||||
if (creationInfo.OwnerId == 0)
|
||||
{
|
||||
creationInfo.OwnerId = 0;
|
||||
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
|
||||
}
|
||||
|
||||
Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt);
|
||||
|
@ -239,7 +229,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
// Workaround that by setting the application ID if it's not already set
|
||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
||||
{
|
||||
attribute.ProgramId = new ProgramId(context.Process.TitleId);
|
||||
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
|
||||
}
|
||||
|
||||
Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
|
||||
|
@ -280,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
// Workaround that by setting the application ID if it's not already set
|
||||
if (attribute.ProgramId == ProgramId.InvalidId)
|
||||
{
|
||||
attribute.ProgramId = new ProgramId(context.Process.TitleId);
|
||||
attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
|
||||
}
|
||||
|
||||
Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
|
||||
|
@ -328,7 +318,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
filter.SetSaveDataType(SaveDataType.Cache);
|
||||
filter.SetProgramId(new ProgramId(context.Process.TitleId));
|
||||
|
||||
// FS would query the User and SdCache space IDs to find where the existing cache is (if any).
|
||||
// FS would query the User and SdCache space IDs to find where the existing cache is (if any).
|
||||
// We always have the SD card inserted, so we can always use SdCache for now.
|
||||
Result result = _baseFileSystemProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(
|
||||
out ReferenceCountedDisposable<LibHac.FsSrv.ISaveDataInfoReader> infoReader, SaveDataSpaceId.SdCache);
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
|||
class IAppletResource : IpcService
|
||||
{
|
||||
private KSharedMemory _hidSharedMem;
|
||||
private int _hidSharedMemHandle;
|
||||
|
||||
public IAppletResource(KSharedMemory hidSharedMem)
|
||||
{
|
||||
|
@ -18,12 +19,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
|||
// GetSharedMemoryHandle() -> handle<copy>
|
||||
public ResultCode GetSharedMemoryHandle(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success)
|
||||
if (_hidSharedMemHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out _hidSharedMemHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_hidSharedMemHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
private HidAccelerometerParameters _accelerometerParams;
|
||||
private HidVibrationValue _vibrationValue;
|
||||
|
||||
public IHidServer(ServiceCtx context) : base(new ServerBase("HidServer"))
|
||||
public IHidServer(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "HidServer"))
|
||||
{
|
||||
_xpadIdEvent = new KEvent(context.Device.System.KernelContext);
|
||||
_palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);
|
||||
|
@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
ControllerType type = (ControllerType)context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
type
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
type
|
||||
});
|
||||
|
||||
context.Device.Hid.Npads.SupportedStyleSets = type;
|
||||
|
@ -577,9 +577,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.SupportedStyleSets
|
||||
context.Device.Hid.Npads.SupportedStyleSets
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -704,9 +704,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.JoyHold
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.JoyHold
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -720,9 +720,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.JoyHold
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.JoyHold
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -17,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
|
||||
public ServerBase Server { get; private set; }
|
||||
|
||||
private IpcService _parent;
|
||||
private IdDictionary _domainObjects;
|
||||
private int _selfId;
|
||||
private bool _isDomain;
|
||||
|
@ -32,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
|
||||
Server = server;
|
||||
|
||||
_parent = this;
|
||||
_domainObjects = new IdDictionary();
|
||||
_selfId = -1;
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
int domainWord0 = context.RequestData.ReadInt32();
|
||||
int domainObjId = context.RequestData.ReadInt32();
|
||||
|
||||
int domainCmd = (domainWord0 >> 0) & 0xff;
|
||||
int inputObjCount = (domainWord0 >> 8) & 0xff;
|
||||
int domainCmd = (domainWord0 >> 0) & 0xff;
|
||||
int inputObjCount = (domainWord0 >> 8) & 0xff;
|
||||
int dataPayloadSize = (domainWord0 >> 16) & 0xffff;
|
||||
|
||||
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
||||
|
@ -96,8 +96,8 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
}
|
||||
}
|
||||
|
||||
long sfciMagic = context.RequestData.ReadInt64();
|
||||
int commandId = (int)context.RequestData.ReadInt64();
|
||||
long sfciMagic = context.RequestData.ReadInt64();
|
||||
int commandId = (int)context.RequestData.ReadInt64();
|
||||
|
||||
bool serviceExists = service.Commands.TryGetValue(commandId, out MethodInfo processRequest);
|
||||
|
||||
|
@ -145,56 +145,37 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
{
|
||||
string dbgMessage = $"{service.GetType().FullName}: {commandId}";
|
||||
|
||||
throw new ServiceNotImplementedException(context, dbgMessage);
|
||||
throw new ServiceNotImplementedException(service, context, dbgMessage);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void MakeObject(ServiceCtx context, IpcService obj)
|
||||
protected void MakeObject(ServiceCtx context, IpcService obj)
|
||||
{
|
||||
IpcService service = context.Session.Service;
|
||||
obj.TrySetServer(_parent.Server);
|
||||
|
||||
obj.TrySetServer(service.Server);
|
||||
|
||||
if (service._isDomain)
|
||||
if (_parent._isDomain)
|
||||
{
|
||||
context.Response.ObjectIds.Add(service.Add(obj));
|
||||
obj._parent = _parent;
|
||||
|
||||
context.Response.ObjectIds.Add(_parent.Add(obj));
|
||||
}
|
||||
else
|
||||
{
|
||||
KSession session = new KSession(context.Device.System.KernelContext);
|
||||
context.Device.System.KernelContext.Syscall.CreateSession(false, 0, out int serverSessionHandle, out int clientSessionHandle);
|
||||
|
||||
session.ClientSession.Service = obj;
|
||||
obj.Server.AddSessionObj(serverSessionHandle, obj);
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(session.ClientSession, out int handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
session.ServerSession.DecrementReferenceCount();
|
||||
session.ClientSession.DecrementReferenceCount();
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeMove(clientSessionHandle);
|
||||
}
|
||||
}
|
||||
|
||||
protected static T GetObject<T>(ServiceCtx context, int index) where T : IpcService
|
||||
protected T GetObject<T>(ServiceCtx context, int index) where T : IpcService
|
||||
{
|
||||
IpcService service = context.Session.Service;
|
||||
|
||||
if (!service._isDomain)
|
||||
{
|
||||
int handle = context.Request.HandleDesc.ToMove[index];
|
||||
|
||||
KClientSession session = context.Process.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
return session?.Service is T ? (T)session.Service : null;
|
||||
}
|
||||
|
||||
int objId = context.Request.ObjectIds[index];
|
||||
|
||||
IIpcService obj = service.GetObject(objId);
|
||||
IIpcService obj = _parent.GetObject(objId);
|
||||
|
||||
return obj is T ? (T)obj : null;
|
||||
return obj is T t ? t : null;
|
||||
}
|
||||
|
||||
public bool TrySetServer(ServerBase newServer)
|
||||
|
@ -230,5 +211,10 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
{
|
||||
return _domainObjects.GetData<IIpcService>(id);
|
||||
}
|
||||
|
||||
public void SetParent(IpcService parent)
|
||||
{
|
||||
_parent = parent._parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,98 +103,98 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
// StartDetection(bytes<8, 4>)
|
||||
public ResultCode StartDetection(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(4)]
|
||||
// StopDetection(bytes<8, 4>)
|
||||
public ResultCode StopDetection(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(5)]
|
||||
// Mount(bytes<8, 4>, u32, u32)
|
||||
public ResultCode Mount(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(6)]
|
||||
// Unmount(bytes<8, 4>)
|
||||
public ResultCode Unmount(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(7)]
|
||||
// OpenApplicationArea(bytes<8, 4>, u32)
|
||||
public ResultCode OpenApplicationArea(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(8)]
|
||||
// GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
|
||||
public ResultCode GetApplicationArea(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(9)]
|
||||
// SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
|
||||
public ResultCode SetApplicationArea(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(10)]
|
||||
// Flush(bytes<8, 4>)
|
||||
public ResultCode Flush(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(11)]
|
||||
// Restore(bytes<8, 4>)
|
||||
public ResultCode Restore(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(12)]
|
||||
// CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
|
||||
public ResultCode CreateApplicationArea(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(13)]
|
||||
// GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
|
||||
public ResultCode GetTagInfo(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(14)]
|
||||
// GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
|
||||
public ResultCode GetRegisterInfo(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(15)]
|
||||
// GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
|
||||
public ResultCode GetCommonInfo(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(16)]
|
||||
// GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
|
||||
public ResultCode GetModelInfo(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(17)]
|
||||
|
@ -308,7 +308,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
// GetApplicationAreaSize(bytes<8, 4>) -> u32
|
||||
public ResultCode GetApplicationAreaSize(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(23)] // 3.0.0+
|
||||
|
@ -334,7 +334,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
// RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
|
||||
public ResultCode RecreateApplicationArea(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
|
|||
private KEvent _event0;
|
||||
private KEvent _event1;
|
||||
|
||||
private int _event0Handle;
|
||||
private int _event1Handle;
|
||||
|
||||
private uint _version;
|
||||
|
||||
public IRequest(Horizon system, uint version)
|
||||
|
@ -50,17 +53,23 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
|
|||
// GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
|
||||
public ResultCode GetSystemEventReadableHandles(ServiceCtx context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success)
|
||||
if (_event0Handle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success)
|
||||
if (_event1Handle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_event0Handle, _event1Handle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -107,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
|
|||
return ResultCode.Unknown180;
|
||||
}
|
||||
|
||||
// Returns appletId, libraryAppletMode, outSize and a buffer.
|
||||
// Returns appletId, libraryAppletMode, outSize and a buffer.
|
||||
// Returned applet ids- (0x19, 0xf, 0xe)
|
||||
// libraryAppletMode seems to be 0 for all applets supported.
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
|
|||
{
|
||||
private readonly KEvent _event;
|
||||
|
||||
private int _eventHandle;
|
||||
|
||||
public IShopServiceAccessor(Horizon system)
|
||||
{
|
||||
_event = new KEvent(system.KernelContext);
|
||||
|
@ -22,12 +24,15 @@ namespace Ryujinx.HLE.HOS.Services.Nim.ShopServiceAccessServerInterface.ShopServ
|
|||
{
|
||||
MakeObject(context, new IShopServiceAsync());
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_eventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceNim);
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
[Service("aoc:u")]
|
||||
class IAddOnContentManager : IpcService
|
||||
{
|
||||
KEvent _addOnContentListChangedEvent;
|
||||
private readonly KEvent _addOnContentListChangedEvent;
|
||||
|
||||
private int _addOnContentListChangedEventHandle;
|
||||
|
||||
public IAddOnContentManager(ServiceCtx context)
|
||||
{
|
||||
|
@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
long pid = context.Process.Pid;
|
||||
|
||||
// Official code checks ApplicationControlProperty.RuntimeAddOnContentInstall
|
||||
// Official code checks ApplicationControlProperty.RuntimeAddOnContentInstall
|
||||
// if true calls ns:am ListAvailableAddOnContent again to get updated count
|
||||
|
||||
byte runtimeAddOnContentInstall = context.Device.Application.ControlData.Value.RuntimeAddOnContentInstall;
|
||||
|
@ -135,12 +137,15 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
// Official code seems to make an internal call to ns:am Cmd 84 GetDynamicCommitEvent()
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (_addOnContentListChangedEventHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_addOnContentListChangedEventHandle);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceNs);
|
||||
|
||||
|
@ -148,7 +153,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
}
|
||||
|
||||
|
||||
[Command(9)] // [10.0.0+]
|
||||
[Command(9)] // [10.0.0+]
|
||||
// GetAddOnContentLostErrorCode() -> u64
|
||||
public ResultCode GetAddOnContentLostErrorCode(ServiceCtx context)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@ using Ryujinx.Cpu;
|
|||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
||||
|
@ -12,6 +11,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
|
|||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
@ -27,47 +27,45 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
private static Dictionary<string, Type> _deviceFileRegistry =
|
||||
new Dictionary<string, Type>()
|
||||
{
|
||||
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
||||
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
||||
{ "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
|
||||
{ "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) },
|
||||
{ "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) },
|
||||
//{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) },
|
||||
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
||||
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
||||
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
||||
{ "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuDeviceFile) },
|
||||
{ "/dev/nvhost-as-gpu", typeof(NvHostAsGpuDeviceFile) },
|
||||
{ "/dev/nvhost-gpu", typeof(NvHostGpuDeviceFile) },
|
||||
//{ "/dev/nvhost-msenc", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvhost-nvdec", typeof(NvHostChannelDeviceFile) },
|
||||
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
||||
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
||||
};
|
||||
|
||||
private static IdDictionary _deviceFileIdRegistry = new IdDictionary();
|
||||
|
||||
private KProcess _owner;
|
||||
private IVirtualMemoryManager _clientMemory;
|
||||
private long _owner;
|
||||
|
||||
private bool _transferMemInitialized = false;
|
||||
|
||||
public INvDrvServices(ServiceCtx context) : base(new ServerBase("NvservicesServer"))
|
||||
public INvDrvServices(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "NvservicesServer"))
|
||||
{
|
||||
_owner = null;
|
||||
_owner = 0;
|
||||
}
|
||||
|
||||
private int Open(ServiceCtx context, string path)
|
||||
{
|
||||
if (context.Process == _owner)
|
||||
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
|
||||
{
|
||||
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
|
||||
{
|
||||
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx) });
|
||||
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(long) });
|
||||
|
||||
NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke(new object[] { context });
|
||||
NvDeviceFile deviceFile = (NvDeviceFile)constructor.Invoke(new object[] { context, _clientMemory, _owner });
|
||||
|
||||
deviceFile.Path = path;
|
||||
deviceFile.Path = path;
|
||||
|
||||
return _deviceFileIdRegistry.Add(deviceFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
||||
}
|
||||
return _deviceFileIdRegistry.Add(deviceFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -150,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
return NvResult.NotImplemented;
|
||||
}
|
||||
|
||||
if (deviceFile.Owner.Pid != _owner.Pid)
|
||||
if (deviceFile.Owner != _owner)
|
||||
{
|
||||
return NvResult.AccessDenied;
|
||||
}
|
||||
|
@ -160,7 +158,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
|
||||
private NvResult EnsureInitialized()
|
||||
{
|
||||
if (_owner == null)
|
||||
if (_owner == 0)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceNv, "INvDrvServices is not initialized!");
|
||||
|
||||
|
@ -229,8 +227,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
if (errorCode == NvResult.Success)
|
||||
{
|
||||
long pathPtr = context.Request.SendBuff[0].Position;
|
||||
long pathSize = context.Request.SendBuff[0].Size;
|
||||
|
||||
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr);
|
||||
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr, pathSize);
|
||||
|
||||
fd = Open(context, path);
|
||||
|
||||
|
@ -322,7 +321,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
// TODO: When transfer memory will be implemented, this could be removed.
|
||||
_transferMemInitialized = true;
|
||||
|
||||
_owner = context.Process;
|
||||
int clientHandle = context.Request.HandleDesc.ToCopy[0];
|
||||
|
||||
_clientMemory = context.Process.HandleTable.GetKProcess(clientHandle).CpuMemory;
|
||||
|
||||
context.Device.System.KernelContext.Syscall.GetProcessId(clientHandle, out _owner);
|
||||
|
||||
context.ResponseData.Write((uint)NvResult.Success);
|
||||
|
||||
|
@ -425,7 +428,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
// ForceSetClientPid(u64) -> u32 error_code
|
||||
public ResultCode ForceSetClientPid(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(8)]
|
||||
|
@ -452,7 +455,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
// InitializeDevtools(u32, handle<copy>) -> u32 error_code;
|
||||
public ResultCode InitializeDevtools(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(11)] // 3.0.0+
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
@ -12,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices
|
|||
abstract class NvDeviceFile
|
||||
{
|
||||
public readonly ServiceCtx Context;
|
||||
public readonly KProcess Owner;
|
||||
public readonly long Owner;
|
||||
|
||||
public string Path;
|
||||
|
||||
public NvDeviceFile(ServiceCtx context)
|
||||
public NvDeviceFile(ServiceCtx context, long owner)
|
||||
{
|
||||
Context = context;
|
||||
Owner = context.Process;
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public virtual NvInternalResult QueryEvent(out int eventHandle, uint eventId)
|
||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Graphics.Gpu.Memory;
|
|||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
@ -12,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
{
|
||||
private static ConcurrentDictionary<KProcess, AddressSpaceContext> _addressSpaceContextRegistry = new ConcurrentDictionary<KProcess, AddressSpaceContext>();
|
||||
|
||||
public NvHostAsGpuDeviceFile(ServiceCtx context) : base(context) { }
|
||||
public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner) { }
|
||||
|
||||
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
|
|||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -19,9 +20,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
private uint _submitTimeout;
|
||||
private uint _timeslice;
|
||||
|
||||
private Switch _device;
|
||||
private readonly Switch _device;
|
||||
|
||||
private Cpu.MemoryManager _memory;
|
||||
private readonly IVirtualMemoryManager _memory;
|
||||
|
||||
public enum ResourcePolicy
|
||||
{
|
||||
|
@ -37,10 +38,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
private NvFence _channelSyncpoint;
|
||||
|
||||
public NvHostChannelDeviceFile(ServiceCtx context) : base(context)
|
||||
public NvHostChannelDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||
{
|
||||
_device = context.Device;
|
||||
_memory = context.Memory;
|
||||
_memory = memory;
|
||||
_timeout = 3000;
|
||||
_submitTimeout = 0;
|
||||
_timeslice = 0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
|
@ -11,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
private KEvent _smExceptionBptPauseReportEvent;
|
||||
private KEvent _errorNotifierEvent;
|
||||
|
||||
public NvHostGpuDeviceFile(ServiceCtx context) : base(context)
|
||||
public NvHostGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, memory, owner)
|
||||
{
|
||||
_smExceptionBptIntReportEvent = new KEvent(context.Device.System.KernelContext);
|
||||
_smExceptionBptPauseReportEvent = new KEvent(context.Device.System.KernelContext);
|
||||
|
@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
if (targetEvent != null)
|
||||
{
|
||||
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using Ryujinx.HLE.HOS.Kernel.Threading;
|
|||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Settings;
|
||||
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
|
|||
private Switch _device;
|
||||
private NvHostEvent[] _events;
|
||||
|
||||
public NvHostCtrlDeviceFile(ServiceCtx context) : base(context)
|
||||
public NvHostCtrlDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||
{
|
||||
if (NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting))
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
|
|||
|
||||
if (targetEvent != null)
|
||||
{
|
||||
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
|
|||
private KEvent _errorEvent;
|
||||
private KEvent _unknownEvent;
|
||||
|
||||
public NvHostCtrlGpuDeviceFile(ServiceCtx context) : base(context)
|
||||
public NvHostCtrlGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||
{
|
||||
_errorEvent = new KEvent(context.Device.System.KernelContext);
|
||||
_unknownEvent = new KEvent(context.Device.System.KernelContext);
|
||||
|
@ -98,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu
|
|||
|
||||
if (targetEvent != null)
|
||||
{
|
||||
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
@ -11,9 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||
{
|
||||
private const int FlagNotFreedYet = 1;
|
||||
|
||||
private static ConcurrentDictionary<KProcess, IdDictionary> _maps = new ConcurrentDictionary<KProcess, IdDictionary>();
|
||||
private static ConcurrentDictionary<long, IdDictionary> _maps = new ConcurrentDictionary<long, IdDictionary>();
|
||||
|
||||
public NvMapDeviceFile(ServiceCtx context) : base(context)
|
||||
public NvMapDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||
{
|
||||
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
|
||||
|
||||
|
@ -244,9 +244,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||
return dict.Add(map);
|
||||
}
|
||||
|
||||
private static bool DeleteMapWithHandle(KProcess process, int handle)
|
||||
private static bool DeleteMapWithHandle(long pid, int handle)
|
||||
{
|
||||
if (_maps.TryGetValue(process, out IdDictionary dict))
|
||||
if (_maps.TryGetValue(pid, out IdDictionary dict))
|
||||
{
|
||||
return dict.Delete(handle) != null;
|
||||
}
|
||||
|
@ -254,14 +254,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||
return false;
|
||||
}
|
||||
|
||||
public static void IncrementMapRefCount(KProcess process, int handle, bool allowHandleZero = false)
|
||||
public static void IncrementMapRefCount(long pid, int handle, bool allowHandleZero = false)
|
||||
{
|
||||
GetMapFromHandle(process, handle, allowHandleZero)?.IncrementRefCount();
|
||||
GetMapFromHandle(pid, handle, allowHandleZero)?.IncrementRefCount();
|
||||
}
|
||||
|
||||
public static bool DecrementMapRefCount(KProcess process, int handle)
|
||||
public static bool DecrementMapRefCount(long pid, int handle)
|
||||
{
|
||||
NvMapHandle map = GetMapFromHandle(process, handle, false);
|
||||
NvMapHandle map = GetMapFromHandle(pid, handle, false);
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
|
@ -270,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||
|
||||
if (map.DecrementRefCount() <= 0)
|
||||
{
|
||||
DeleteMapWithHandle(process, handle);
|
||||
DeleteMapWithHandle(pid, handle);
|
||||
|
||||
Logger.Info?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
|
||||
|
||||
|
@ -282,9 +282,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||
}
|
||||
}
|
||||
|
||||
public static NvMapHandle GetMapFromHandle(KProcess process, int handle, bool allowHandleZero = false)
|
||||
public static NvMapHandle GetMapFromHandle(long pid, int handle, bool allowHandleZero = false)
|
||||
{
|
||||
if ((allowHandleZero || handle != 0) && _maps.TryGetValue(process, out IdDictionary dict))
|
||||
if ((allowHandleZero || handle != 0) && _maps.TryGetValue(pid, out IdDictionary dict))
|
||||
{
|
||||
return dict.GetData<NvMapHandle>(handle);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
return ResultCode.InvalidAddress;
|
||||
}
|
||||
|
||||
StructReader reader = new StructReader(context.Memory, nrrAddress);
|
||||
StructReader reader = new StructReader(_owner.CpuMemory, nrrAddress);
|
||||
NrrHeader header = reader.Read<NrrHeader>();
|
||||
|
||||
if (header.Magic != NrrMagic)
|
||||
|
@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
{
|
||||
byte[] temp = new byte[0x20];
|
||||
|
||||
context.Memory.Read((ulong)(nrrAddress + header.HashOffset + (i * 0x20)), temp);
|
||||
_owner.CpuMemory.Read((ulong)(nrrAddress + header.HashOffset + (i * 0x20)), temp);
|
||||
|
||||
hashes.Add(temp);
|
||||
}
|
||||
|
@ -131,8 +131,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
return ResultCode.InvalidAddress;
|
||||
}
|
||||
|
||||
uint magic = context.Memory.Read<uint>(nroAddress + 0x10);
|
||||
uint nroFileSize = context.Memory.Read<uint>(nroAddress + 0x18);
|
||||
uint magic = _owner.CpuMemory.Read<uint>(nroAddress + 0x10);
|
||||
uint nroFileSize = _owner.CpuMemory.Read<uint>(nroAddress + 0x18);
|
||||
|
||||
if (magic != NroMagic || nroSize != nroFileSize)
|
||||
{
|
||||
|
@ -141,7 +141,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
|
||||
byte[] nroData = new byte[nroSize];
|
||||
|
||||
context.Memory.Read(nroAddress, nroData);
|
||||
_owner.CpuMemory.Read(nroAddress, nroData);
|
||||
|
||||
byte[] nroHash = null;
|
||||
|
||||
|
@ -176,7 +176,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
// Check if everything is contiguous.
|
||||
if (nro.RoOffset != nro.TextOffset + nro.Text.Length ||
|
||||
nro.DataOffset != nro.RoOffset + nro.Ro.Length ||
|
||||
nroFileSize != nro.DataOffset + nro.Data.Length)
|
||||
nroFileSize != nro.DataOffset + nro.Data.Length)
|
||||
{
|
||||
return ResultCode.InvalidNro;
|
||||
}
|
||||
|
@ -337,21 +337,21 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
|
||||
KernelResult result;
|
||||
|
||||
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, MemoryPermission.ReadAndExecute);
|
||||
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, KMemoryPermission.ReadAndExecute);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, MemoryPermission.Read);
|
||||
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, KMemoryPermission.Read);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, MemoryPermission.ReadAndWrite);
|
||||
return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, KMemoryPermission.ReadAndWrite);
|
||||
}
|
||||
|
||||
private ResultCode RemoveNrrInfo(long nrrAddress)
|
||||
|
@ -420,9 +420,9 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
return (ResultCode)result;
|
||||
}
|
||||
|
||||
private ResultCode IsInitialized(KProcess process)
|
||||
private ResultCode IsInitialized(long pid)
|
||||
{
|
||||
if (_owner != null && _owner.Pid == process.Pid)
|
||||
if (_owner != null && _owner.Pid == pid)
|
||||
{
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
// LoadNro(u64, u64, u64, u64, u64, pid) -> u64
|
||||
public ResultCode LoadNro(ServiceCtx context)
|
||||
{
|
||||
ResultCode result = IsInitialized(context.Process);
|
||||
ResultCode result = IsInitialized(_owner.Pid);
|
||||
|
||||
// Zero
|
||||
context.RequestData.ReadUInt64();
|
||||
|
@ -454,11 +454,11 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
result = MapNro(context.Process, info, out nroMappedAddress);
|
||||
result = MapNro(_owner, info, out nroMappedAddress);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
result = (ResultCode)SetNroMemoryPermissions(context.Process, info.Executable, nroMappedAddress);
|
||||
result = (ResultCode)SetNroMemoryPermissions(_owner, info.Executable, nroMappedAddress);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
|
@ -479,7 +479,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
// UnloadNro(u64, u64, pid)
|
||||
public ResultCode UnloadNro(ServiceCtx context)
|
||||
{
|
||||
ResultCode result = IsInitialized(context.Process);
|
||||
ResultCode result = IsInitialized(_owner.Pid);
|
||||
|
||||
// Zero
|
||||
context.RequestData.ReadUInt64();
|
||||
|
@ -503,7 +503,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
// LoadNrr(u64, u64, u64, pid)
|
||||
public ResultCode LoadNrr(ServiceCtx context)
|
||||
{
|
||||
ResultCode result = IsInitialized(context.Process);
|
||||
ResultCode result = IsInitialized(_owner.Pid);
|
||||
|
||||
// pid placeholder, zero
|
||||
context.RequestData.ReadUInt64();
|
||||
|
@ -536,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
// UnloadNrr(u64, u64, pid)
|
||||
public ResultCode UnloadNrr(ServiceCtx context)
|
||||
{
|
||||
ResultCode result = IsInitialized(context.Process);
|
||||
ResultCode result = IsInitialized(_owner.Pid);
|
||||
|
||||
// pid placeholder, zero
|
||||
context.RequestData.ReadUInt64();
|
||||
|
@ -565,7 +565,8 @@ namespace Ryujinx.HLE.HOS.Services.Ro
|
|||
return ResultCode.InvalidSession;
|
||||
}
|
||||
|
||||
_owner = context.Process;
|
||||
_owner = context.Process.HandleTable.GetKProcess(context.Request.HandleDesc.ToCopy[0]);
|
||||
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
|
|||
[Service("pl:s")] // 9.0.0+
|
||||
class ISharedFontManager : IpcService
|
||||
{
|
||||
private int _fontSharedMemHandle;
|
||||
|
||||
public ISharedFontManager(ServiceCtx context) { }
|
||||
|
||||
[Command(0)]
|
||||
|
@ -63,12 +65,15 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
|
|||
{
|
||||
context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager);
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out int handle) != KernelResult.Success)
|
||||
if (_fontSharedMemHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out _fontSharedMemHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_fontSharedMemHandle);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -1,62 +1,193 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services
|
||||
{
|
||||
class ServerBase
|
||||
{
|
||||
private struct IpcRequest
|
||||
{
|
||||
public Switch Device { get; }
|
||||
public KProcess Process => Thread?.Owner;
|
||||
public KThread Thread { get; }
|
||||
public KClientSession Session { get; }
|
||||
public ulong MessagePtr { get; }
|
||||
public ulong MessageSize { get; }
|
||||
// Must be the maximum value used by services (highest one know is the one used by nvservices = 0x8000).
|
||||
// Having a size that is too low will cause failures as data copy will fail if the receiving buffer is
|
||||
// not large enough.
|
||||
private const int PointerBufferSize = 0x8000;
|
||||
|
||||
public IpcRequest(Switch device, KThread thread, KClientSession session, ulong messagePtr, ulong messageSize)
|
||||
private readonly static int[] DefaultCapabilities = new int[]
|
||||
{
|
||||
0x030363F7,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
0x0048BFFF,
|
||||
0x01007FFF
|
||||
};
|
||||
|
||||
private readonly KernelContext _context;
|
||||
private readonly KProcess _selfProcess;
|
||||
|
||||
private readonly List<int> _sessionHandles = new List<int>();
|
||||
private readonly List<int> _portHandles = new List<int>();
|
||||
private readonly Dictionary<int, IpcService> _sessions = new Dictionary<int, IpcService>();
|
||||
private readonly Dictionary<int, IpcService> _ports = new Dictionary<int, IpcService>();
|
||||
|
||||
public ManualResetEvent InitDone { get; }
|
||||
public IpcService SmObject { get; set; }
|
||||
public string Name { get; }
|
||||
|
||||
public ServerBase(KernelContext context, string name)
|
||||
{
|
||||
InitDone = new ManualResetEvent(false);
|
||||
Name = name;
|
||||
_context = context;
|
||||
|
||||
const ProcessCreationFlags flags =
|
||||
ProcessCreationFlags.EnableAslr |
|
||||
ProcessCreationFlags.AddressSpace64Bit |
|
||||
ProcessCreationFlags.Is64Bit |
|
||||
ProcessCreationFlags.PoolPartitionSystem;
|
||||
|
||||
ProcessCreationInfo creationInfo = new ProcessCreationInfo("Service", 1, 0, 0x8000000, 1, flags, 0, 0);
|
||||
|
||||
context.Syscall.CreateProcess(creationInfo, DefaultCapabilities, out int handle, null, ServerLoop);
|
||||
|
||||
_selfProcess = context.Scheduler.GetCurrentProcess().HandleTable.GetKProcess(handle);
|
||||
|
||||
context.Syscall.StartProcess(handle, 44, 3, 0x1000);
|
||||
}
|
||||
|
||||
private void AddPort(int serverPortHandle, IpcService obj)
|
||||
{
|
||||
_portHandles.Add(serverPortHandle);
|
||||
_ports.Add(serverPortHandle, obj);
|
||||
}
|
||||
|
||||
public void AddSessionObj(KServerSession serverSession, IpcService obj)
|
||||
{
|
||||
_selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle);
|
||||
AddSessionObj(serverSessionHandle, obj);
|
||||
}
|
||||
|
||||
public void AddSessionObj(int serverSessionHandle, IpcService obj)
|
||||
{
|
||||
_sessionHandles.Add(serverSessionHandle);
|
||||
_sessions.Add(serverSessionHandle, obj);
|
||||
}
|
||||
|
||||
private void ServerLoop()
|
||||
{
|
||||
if (SmObject != null)
|
||||
{
|
||||
Device = device;
|
||||
Thread = thread;
|
||||
Session = session;
|
||||
MessagePtr = messagePtr;
|
||||
MessageSize = messageSize;
|
||||
_context.Syscall.ManageNamedPort("sm:", 50, out int serverPortHandle);
|
||||
|
||||
AddPort(serverPortHandle, SmObject);
|
||||
|
||||
InitDone.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
InitDone.Dispose();
|
||||
}
|
||||
|
||||
public void SignalDone(KernelResult result)
|
||||
KThread thread = _context.Scheduler.GetCurrentThread();
|
||||
ulong messagePtr = thread.TlsAddress;
|
||||
_context.Syscall.SetHeapSize(0x200000, out ulong heapAddr);
|
||||
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
|
||||
|
||||
int replyTargetHandle = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Thread.ObjSyncResult = result;
|
||||
Thread.Reschedule(ThreadSchedState.Running);
|
||||
int[] handles = _portHandles.ToArray();
|
||||
|
||||
for (int i = 0; i < handles.Length; i++)
|
||||
{
|
||||
if (_context.Syscall.AcceptSession(handles[i], out int serverSessionHandle) == KernelResult.Success)
|
||||
{
|
||||
AddSessionObj(serverSessionHandle, _ports[handles[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
handles = _sessionHandles.ToArray();
|
||||
|
||||
var rc = _context.Syscall.ReplyAndReceive(handles, replyTargetHandle, 1000000L, out int signaledIndex);
|
||||
|
||||
thread.HandlePostSyscall();
|
||||
|
||||
if (!thread.Context.Running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
replyTargetHandle = 0;
|
||||
|
||||
if (rc == KernelResult.Success && signaledIndex != -1)
|
||||
{
|
||||
int signaledHandle = handles[signaledIndex];
|
||||
|
||||
if (Process(signaledHandle, heapAddr))
|
||||
{
|
||||
replyTargetHandle = signaledHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly AsyncWorkQueue<IpcRequest> _ipcProcessor;
|
||||
|
||||
public ServerBase(string name)
|
||||
private bool Process(int serverSessionHandle, ulong recvListAddr)
|
||||
{
|
||||
_ipcProcessor = new AsyncWorkQueue<IpcRequest>(Process, name);
|
||||
}
|
||||
KProcess process = _context.Scheduler.GetCurrentProcess();
|
||||
KThread thread = _context.Scheduler.GetCurrentThread();
|
||||
ulong messagePtr = thread.TlsAddress;
|
||||
ulong messageSize = 0x100;
|
||||
|
||||
public void PushMessage(Switch device, KThread thread, KClientSession session, ulong messagePtr, ulong messageSize)
|
||||
{
|
||||
_ipcProcessor.Add(new IpcRequest(device, thread, session, messagePtr, messageSize));
|
||||
}
|
||||
byte[] reqData = new byte[messageSize];
|
||||
|
||||
private void Process(IpcRequest message)
|
||||
{
|
||||
byte[] reqData = new byte[message.MessageSize];
|
||||
process.CpuMemory.Read(messagePtr, reqData);
|
||||
|
||||
message.Process.CpuMemory.Read(message.MessagePtr, reqData);
|
||||
|
||||
IpcMessage request = new IpcMessage(reqData, (long)message.MessagePtr);
|
||||
IpcMessage request = new IpcMessage(reqData, (long)messagePtr);
|
||||
IpcMessage response = new IpcMessage();
|
||||
|
||||
ulong tempAddr = recvListAddr;
|
||||
int sizesOffset = request.RawData.Length - ((request.RecvListBuff.Count * 2 + 3) & ~3);
|
||||
|
||||
bool noReceive = true;
|
||||
|
||||
for (int i = 0; i < request.ReceiveBuff.Count; i++)
|
||||
{
|
||||
noReceive &= (request.ReceiveBuff[i].Position == 0);
|
||||
}
|
||||
|
||||
if (noReceive)
|
||||
{
|
||||
for (int i = 0; i < request.RecvListBuff.Count; i++)
|
||||
{
|
||||
int size = BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan().Slice(sizesOffset + i * 2, 2));
|
||||
|
||||
response.PtrBuff.Add(new IpcPtrBuffDesc((long)tempAddr, i, size));
|
||||
|
||||
request.RecvListBuff[i] = new IpcRecvListBuffDesc((long)tempAddr, size);
|
||||
|
||||
tempAddr += (ulong)size;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldReply = true;
|
||||
|
||||
using (MemoryStream raw = new MemoryStream(request.RawData))
|
||||
{
|
||||
BinaryReader reqReader = new BinaryReader(raw);
|
||||
|
@ -71,17 +202,16 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
BinaryWriter resWriter = new BinaryWriter(resMs);
|
||||
|
||||
ServiceCtx context = new ServiceCtx(
|
||||
message.Device,
|
||||
message.Process,
|
||||
message.Process.CpuMemory,
|
||||
message.Thread,
|
||||
message.Session,
|
||||
_context.Device,
|
||||
process,
|
||||
process.CpuMemory,
|
||||
thread,
|
||||
request,
|
||||
response,
|
||||
reqReader,
|
||||
resWriter);
|
||||
|
||||
message.Session.Service.CallMethod(context);
|
||||
_sessions[serverSessionHandle].CallMethod(context);
|
||||
|
||||
response.RawData = resMs.ToArray();
|
||||
}
|
||||
|
@ -95,11 +225,11 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
switch (cmdId)
|
||||
{
|
||||
case 0:
|
||||
request = FillResponse(response, 0, message.Session.Service.ConvertToDomain());
|
||||
request = FillResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain());
|
||||
break;
|
||||
|
||||
case 3:
|
||||
request = FillResponse(response, 0, 0x1000);
|
||||
request = FillResponse(response, 0, PointerBufferSize);
|
||||
break;
|
||||
|
||||
// TODO: Whats the difference between IpcDuplicateSession/Ex?
|
||||
|
@ -107,12 +237,11 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
case 4:
|
||||
int unknown = reqReader.ReadInt32();
|
||||
|
||||
if (message.Process.HandleTable.GenerateHandle(message.Session, out int handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
_context.Syscall.CreateSession(false, 0, out int dupServerSessionHandle, out int dupClientSessionHandle);
|
||||
|
||||
response.HandleDesc = IpcHandleDesc.MakeMove(handle);
|
||||
AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]);
|
||||
|
||||
response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle);
|
||||
|
||||
request = FillResponse(response, 0);
|
||||
|
||||
|
@ -123,18 +252,24 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
}
|
||||
else if (request.Type == IpcMessageType.CloseSession)
|
||||
{
|
||||
message.SignalDone(KernelResult.PortRemoteClosed);
|
||||
return;
|
||||
_context.Syscall.CloseHandle(serverSessionHandle);
|
||||
_sessionHandles.Remove(serverSessionHandle);
|
||||
IpcService service = _sessions[serverSessionHandle];
|
||||
if (service is IDisposable disposableObj)
|
||||
{
|
||||
disposableObj.Dispose();
|
||||
}
|
||||
_sessions.Remove(serverSessionHandle);
|
||||
shouldReply = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(request.Type.ToString());
|
||||
}
|
||||
|
||||
message.Process.CpuMemory.Write(message.MessagePtr, response.GetBytes((long)message.MessagePtr));
|
||||
process.CpuMemory.Write(messagePtr, response.GetBytes((long)messagePtr, recvListAddr | ((ulong)PointerBufferSize << 48)));
|
||||
return shouldReply;
|
||||
}
|
||||
|
||||
message.SignalDone(KernelResult.Success);
|
||||
}
|
||||
|
||||
private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using System;
|
||||
|
@ -11,18 +12,17 @@ using System.Reflection;
|
|||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sm
|
||||
{
|
||||
[Service("sm:")]
|
||||
class IUserInterface : IpcService
|
||||
{
|
||||
private Dictionary<string, Type> _services;
|
||||
|
||||
private ConcurrentDictionary<string, KPort> _registeredServices;
|
||||
private readonly ConcurrentDictionary<string, KPort> _registeredServices;
|
||||
|
||||
private readonly ServerBase _commonServer;
|
||||
|
||||
private bool _isInitialized;
|
||||
|
||||
public IUserInterface(ServiceCtx context = null) : base(new ServerBase("SmServer"))
|
||||
public IUserInterface(KernelContext context)
|
||||
{
|
||||
_registeredServices = new ConcurrentDictionary<string, KPort>();
|
||||
|
||||
|
@ -31,18 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
.Select(service => (((ServiceAttribute)service).Name, type)))
|
||||
.ToDictionary(service => service.Name, service => service.type);
|
||||
|
||||
_commonServer = new ServerBase("CommonServer");
|
||||
}
|
||||
TrySetServer(new ServerBase(context, "SmServer") { SmObject = this });
|
||||
|
||||
public static void InitializePort(Horizon system)
|
||||
{
|
||||
KPort port = new KPort(system.KernelContext, 256, false, 0);
|
||||
|
||||
port.ClientPort.SetName("sm:");
|
||||
|
||||
IUserInterface smService = new IUserInterface();
|
||||
|
||||
port.ClientPort.Service = smService;
|
||||
_commonServer = new ServerBase(context, "CommonServer");
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
|
@ -92,16 +83,13 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
: (IpcService)Activator.CreateInstance(type, context);
|
||||
|
||||
service.TrySetServer(_commonServer);
|
||||
|
||||
session.ClientSession.Service = service;
|
||||
service.Server.AddSessionObj(session.ServerSession, service);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ServiceConfiguration.IgnoreMissingServices)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
|
||||
|
||||
session.ClientSession.Service = new DummyService(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -142,7 +130,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
|
||||
int maxSessions = context.RequestData.ReadInt32();
|
||||
|
||||
if (name == string.Empty)
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return ResultCode.InvalidName;
|
||||
}
|
||||
|
@ -185,7 +173,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
|
||||
int maxSessions = context.RequestData.ReadInt32();
|
||||
|
||||
if (name == string.Empty)
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return ResultCode.InvalidName;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
|
||||
private List<BsdSocket> _sockets = new List<BsdSocket>();
|
||||
|
||||
public IClient(ServiceCtx context, bool isPrivileged) : base(new ServerBase("BsdServer"))
|
||||
public IClient(ServiceCtx context, bool isPrivileged) : base(new ServerBase(context.Device.System.KernelContext, "BsdServer"))
|
||||
{
|
||||
_isPrivileged = isPrivileged;
|
||||
}
|
||||
|
@ -247,6 +247,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceBsd);
|
||||
|
||||
// Close transfer memory immediately as we don't use it.
|
||||
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -118,14 +118,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
|
|||
// ImportSettings(u32, buffer<unknown, 5>) -> buffer<unknown, 6>
|
||||
public ResultCode ImportSettings(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(15)]
|
||||
// Unknown(bytes<1>)
|
||||
public ResultCode Unknown(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(20)]
|
||||
|
@ -164,49 +164,49 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
|
|||
// GetNasServiceSetting(buffer<unknown<0x10>, 0x15>) -> buffer<unknown<0x108>, 0x16>
|
||||
public ResultCode GetNasServiceSetting(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(31)]
|
||||
// GetNasServiceSettingEx(buffer<unknown<0x10>, 0x15>) -> (u32, buffer<unknown<0x108>, 0x16>)
|
||||
public ResultCode GetNasServiceSettingEx(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(40)]
|
||||
// GetNasRequestFqdn() -> buffer<unknown<0x100>, 0x16>
|
||||
public ResultCode GetNasRequestFqdn(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(41)]
|
||||
// GetNasRequestFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
|
||||
public ResultCode GetNasRequestFqdnEx(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(42)]
|
||||
// GetNasApiFqdn() -> buffer<unknown<0x100>, 0x16>
|
||||
public ResultCode GetNasApiFqdn(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(43)]
|
||||
// GetNasApiFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
|
||||
public ResultCode GetNasApiFqdnEx(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(50)]
|
||||
// GetCurrentSetting() -> buffer<unknown<0x12bf0>, 0x16>
|
||||
public ResultCode GetCurrentSetting(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(60)]
|
||||
|
@ -262,7 +262,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
|
|||
// IsChangeEnvironmentIdentifierDisabled() -> bytes<1>
|
||||
public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context)
|
||||
{
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
{
|
||||
class BufferQueue
|
||||
static class BufferQueue
|
||||
{
|
||||
public static void CreateBufferQueue(Switch device, KProcess process, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
|
||||
public static BufferQueueCore CreateBufferQueue(Switch device, long pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer)
|
||||
{
|
||||
BufferQueueCore core = new BufferQueueCore(device, process);
|
||||
BufferQueueCore core = new BufferQueueCore(device, pid);
|
||||
|
||||
producer = new BufferQueueProducer(core);
|
||||
consumer = new BufferQueueConsumer(core);
|
||||
|
||||
return core;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||
using System;
|
||||
|
@ -40,11 +40,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
private KEvent _waitBufferFreeEvent;
|
||||
private KEvent _frameAvailableEvent;
|
||||
|
||||
public KProcess Owner { get; }
|
||||
public long Owner { get; }
|
||||
|
||||
public bool Active { get; private set; }
|
||||
|
||||
public const int BufferHistoryArraySize = 8;
|
||||
|
||||
public BufferQueueCore(Switch device, KProcess process)
|
||||
public BufferQueueCore(Switch device, long pid)
|
||||
{
|
||||
Slots = new BufferSlotArray();
|
||||
IsAbandoned = false;
|
||||
|
@ -70,7 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
_waitBufferFreeEvent = new KEvent(device.System.KernelContext);
|
||||
_frameAvailableEvent = new KEvent(device.System.KernelContext);
|
||||
|
||||
Owner = process;
|
||||
Owner = pid;
|
||||
|
||||
Active = true;
|
||||
|
||||
BufferHistory = new BufferInfo[BufferHistoryArraySize];
|
||||
EnableExternalEvent = true;
|
||||
|
@ -162,6 +166,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
}
|
||||
}
|
||||
|
||||
public void PrepareForExit()
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
Active = false;
|
||||
|
||||
Monitor.PulseAll(Lock);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find an accurate way to handle a regular condvar here as this will wake up unwanted threads in some edge cases.
|
||||
public void SignalDequeueEvent()
|
||||
{
|
||||
|
@ -170,7 +184,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
public void WaitDequeueEvent()
|
||||
{
|
||||
Monitor.Wait(Lock);
|
||||
Monitor.Exit(Lock);
|
||||
|
||||
KernelStatic.YieldUntilCompletion(WaitForLock);
|
||||
|
||||
Monitor.Enter(Lock);
|
||||
}
|
||||
|
||||
public void SignalIsAllocatingEvent()
|
||||
|
@ -180,7 +198,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
public void WaitIsAllocatingEvent()
|
||||
{
|
||||
Monitor.Wait(Lock);
|
||||
Monitor.Exit(Lock);
|
||||
|
||||
KernelStatic.YieldUntilCompletion(WaitForLock);
|
||||
|
||||
Monitor.Enter(Lock);
|
||||
}
|
||||
|
||||
private void WaitForLock()
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
if (Active)
|
||||
{
|
||||
Monitor.Wait(Lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FreeBufferLocked(int slot)
|
||||
|
|
|
@ -816,6 +816,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
}
|
||||
|
||||
Core.WaitDequeueEvent();
|
||||
|
||||
if (!Core.Active)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
{
|
||||
abstract class IHOSBinderDriver : IpcService
|
||||
{
|
||||
public IHOSBinderDriver() {}
|
||||
public IHOSBinderDriver() { }
|
||||
|
||||
[Command(0)]
|
||||
// TransactParcel(s32, u32, u32, buffer<unknown, 5, 0>) -> buffer<unknown, 6, 0>
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
@ -40,7 +37,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
public int ProducerBinderId;
|
||||
public IGraphicBufferProducer Producer;
|
||||
public BufferItemConsumer Consumer;
|
||||
public KProcess Owner;
|
||||
public BufferQueueCore Core;
|
||||
public long Owner;
|
||||
}
|
||||
|
||||
private class TextureCallbackInformation
|
||||
|
@ -84,7 +82,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
}
|
||||
}
|
||||
|
||||
public IGraphicBufferProducer OpenLayer(KProcess process, long layerId)
|
||||
public IGraphicBufferProducer OpenLayer(long pid, long layerId)
|
||||
{
|
||||
bool needCreate;
|
||||
|
||||
|
@ -95,13 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
if (needCreate)
|
||||
{
|
||||
CreateLayerFromId(process, layerId);
|
||||
CreateLayerFromId(pid, layerId);
|
||||
}
|
||||
|
||||
return GetProducerByLayerId(layerId);
|
||||
}
|
||||
|
||||
public IGraphicBufferProducer CreateLayer(KProcess process, out long layerId)
|
||||
public IGraphicBufferProducer CreateLayer(long pid, out long layerId)
|
||||
{
|
||||
layerId = 1;
|
||||
|
||||
|
@ -116,25 +114,26 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
}
|
||||
}
|
||||
|
||||
CreateLayerFromId(process, layerId);
|
||||
CreateLayerFromId(pid, layerId);
|
||||
|
||||
return GetProducerByLayerId(layerId);
|
||||
}
|
||||
|
||||
private void CreateLayerFromId(KProcess process, long layerId)
|
||||
private void CreateLayerFromId(long pid, long layerId)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.SurfaceFlinger, $"Creating layer {layerId}");
|
||||
|
||||
BufferQueue.CreateBufferQueue(_device, process, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
|
||||
BufferQueueCore core = BufferQueue.CreateBufferQueue(_device, pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
|
||||
|
||||
_layers.Add(layerId, new Layer
|
||||
{
|
||||
ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
|
||||
Producer = producer,
|
||||
Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
|
||||
Owner = process
|
||||
Core = core,
|
||||
Owner = pid
|
||||
});
|
||||
|
||||
LastId = layerId;
|
||||
|
@ -345,6 +344,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
public void Dispose()
|
||||
{
|
||||
_isRunning = false;
|
||||
|
||||
foreach (Layer layer in _layers.Values)
|
||||
{
|
||||
layer.Core.PrepareForExit();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnFrameAvailable(ref BufferItem item)
|
||||
|
|
|
@ -42,23 +42,23 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
Buffer = parcel.ReadUnmanagedType<NvGraphicBuffer>();
|
||||
}
|
||||
|
||||
public void IncrementNvMapHandleRefCount(KProcess process)
|
||||
public void IncrementNvMapHandleRefCount(long pid)
|
||||
{
|
||||
NvMapDeviceFile.IncrementMapRefCount(process, Buffer.NvMapId);
|
||||
NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.NvMapId);
|
||||
|
||||
for (int i = 0; i < Buffer.Surfaces.Length; i++)
|
||||
{
|
||||
NvMapDeviceFile.IncrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
|
||||
NvMapDeviceFile.IncrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public void DecrementNvMapHandleRefCount(KProcess process)
|
||||
public void DecrementNvMapHandleRefCount(long pid)
|
||||
{
|
||||
NvMapDeviceFile.DecrementMapRefCount(process, Buffer.NvMapId);
|
||||
NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.NvMapId);
|
||||
|
||||
for (int i = 0; i < Buffer.Surfaces.Length; i++)
|
||||
{
|
||||
NvMapDeviceFile.DecrementMapRefCount(process, Buffer.Surfaces[i].NvMapHandle);
|
||||
NvMapDeviceFile.DecrementMapRefCount(pid, Buffer.Surfaces[i].NvMapHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,12 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
private IStaticServiceForPsc _inner;
|
||||
private TimePermissions _permissions;
|
||||
|
||||
public IStaticServiceForGlue(ServiceCtx context, TimePermissions permissions) : base(new ServerBase("TimeServer"))
|
||||
public IStaticServiceForGlue(ServiceCtx context, TimePermissions permissions) : base(new ServerBase(context.Device.System.KernelContext, "TimeServer"))
|
||||
{
|
||||
_permissions = permissions;
|
||||
_inner = new IStaticServiceForPsc(context, permissions);
|
||||
_inner.TrySetServer(Server);
|
||||
_inner.SetParent(this);
|
||||
}
|
||||
|
||||
[Command(0)]
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public ResultCode Unknown50(ServiceCtx context)
|
||||
{
|
||||
// TODO: figure out the usage of this event
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(51)]
|
||||
|
@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public ResultCode Unknown51(ServiceCtx context)
|
||||
{
|
||||
// TODO: figure out the usage of this event
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(52)]
|
||||
|
@ -165,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public ResultCode Unknown52(ServiceCtx context)
|
||||
{
|
||||
// TODO: figure out the usage of this event
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(60)]
|
||||
|
@ -201,7 +201,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public ResultCode GetAlarmRegistrationEvent(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(201)]
|
||||
|
@ -209,7 +209,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public ResultCode UpdateSteadyAlarms(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
|
||||
[Command(202)]
|
||||
|
@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
public ResultCode TryGetNextSteadyClockAlarmSnapshot(ServiceCtx context)
|
||||
{
|
||||
// TODO
|
||||
throw new ServiceNotImplementedException(context);
|
||||
throw new ServiceNotImplementedException(this, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
|||
[Service("vi:u")]
|
||||
class IApplicationRootService : IpcService
|
||||
{
|
||||
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
|
||||
public IApplicationRootService(ServiceCtx context) : base(new ServerBase("ViServerU")) { }
|
||||
public IApplicationRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerU")) { }
|
||||
|
||||
[Command(0)]
|
||||
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
|||
class IManagerRootService : IpcService
|
||||
{
|
||||
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
|
||||
public IManagerRootService(ServiceCtx context) : base(new ServerBase("ViServerM")) { }
|
||||
public IManagerRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerM")) { }
|
||||
|
||||
[Command(2)]
|
||||
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
|||
class ISystemRootService : IpcService
|
||||
{
|
||||
// vi:u/m/s aren't on 3 separate threads but we can't put them together with the current ServerBase
|
||||
public ISystemRootService(ServiceCtx context) : base(new ServerBase("ViServerS")) { }
|
||||
public ISystemRootService(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "ViServerS")) { }
|
||||
|
||||
[Command(1)]
|
||||
// GetDisplayService(u32) -> object<nn::visrv::sf::IApplicationDisplayService>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue