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

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

* Fix for applet transfer memory + some nits

* Keep handles if possible to avoid server handle table exhaustion

* Fix IPC ZeroFill bug

* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer

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

* Make it exit properly

* Make ServiceNotImplementedException show the full message again

* Allow yielding execution to avoid starving other threads

* Only wait if active

* Merge IVirtualMemoryManager and IAddressSpaceManager

* Fix Ro loading data from the wrong process

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

View file

@ -66,7 +66,7 @@ namespace ARMeilleure.State
} }
} }
internal bool Running { get; private set; } public bool Running { get; private set; }
public event EventHandler<EventArgs> Interrupt; public event EventHandler<EventArgs> Interrupt;
public event EventHandler<InstExceptionEventArgs> Break; public event EventHandler<InstExceptionEventArgs> Break;

View file

@ -16,7 +16,7 @@
// //
using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Cpu; using Ryujinx.Memory;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -65,7 +65,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
IsEffectEnabled = isEnabled; IsEffectEnabled = isEnabled;
} }
private uint Read(MemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount) private uint Read(IVirtualMemoryManager memoryManager, ulong bufferAddress, uint countMax, Span<int> outBuffer, uint count, uint readOffset, uint updateCount)
{ {
if (countMax == 0 || bufferAddress == 0) if (countMax == 0 || bufferAddress == 0)
{ {
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
return count; return count;
} }
private uint Write(MemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount) private uint Write(IVirtualMemoryManager memoryManager, ulong outBufferAddress, uint countMax, ReadOnlySpan<int> buffer, uint count, uint writeOffset, uint updateCount)
{ {
if (countMax == 0 || outBufferAddress == 0) if (countMax == 0 || outBufferAddress == 0)
{ {
@ -175,8 +175,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>()); ZeroFill(context.MemoryManager, BufferInfo.SendBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
MemoryHelper.FillWithZeros(context.MemoryManager, (long)BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>()); ZeroFill(context.MemoryManager, BufferInfo.ReturnBufferInfo, Unsafe.SizeOf<AuxiliaryBufferInfo>());
if (InputBufferIndex != OutputBufferIndex) if (InputBufferIndex != OutputBufferIndex)
{ {
@ -184,5 +184,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
} }
} }
private static void ZeroFill(IVirtualMemoryManager memoryManager, ulong address, int size)
{
ulong endAddress = address + (ulong)size;
while (address + 7UL < endAddress)
{
memoryManager.Write(address, 0UL);
address += 8;
}
while (address < endAddress)
{
memoryManager.Write(address, (byte)0);
address++;
}
}
} }
} }

View file

@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Integration;
using Ryujinx.Audio.Renderer.Server; using Ryujinx.Audio.Renderer.Server;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -37,7 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public List<ICommand> Commands { get; } public List<ICommand> Commands { get; }
public MemoryManager MemoryManager { get; } public IVirtualMemoryManager MemoryManager { get; }
public HardwareDevice OutputDevice { get; private set; } public HardwareDevice OutputDevice { get; private set; }
@ -50,7 +50,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
{ {
} }
public CommandList(MemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax) public CommandList(IVirtualMemoryManager memoryManager, Memory<float> mixBuffer, uint sampleCount, uint sampleRate, uint mixBufferCount, uint voiceChannelCountMax)
{ {
SampleCount = sampleCount; SampleCount = sampleCount;
SampleRate = sampleRate; SampleRate = sampleRate;

View file

@ -18,7 +18,7 @@
using Ryujinx.Audio.Renderer.Common; using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Memory;
using System; using System;
using System.Buffers; using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
@ -63,7 +63,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
} }
} }
public static void ProcessWaveBuffers(MemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount) public static void ProcessWaveBuffers(IVirtualMemoryManager memoryManager, Span<float> outputBuffer, WaveBufferInformation info, uint targetSampleRate, int sampleCount)
{ {
const int tempBufferSize = 0x3F00; const int tempBufferSize = 0x3F00;

View file

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// //
using Ryujinx.Cpu; using Ryujinx.Memory;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
@ -33,22 +33,22 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
public uint WriteOffset; public uint WriteOffset;
private uint _reserved; private uint _reserved;
public static uint GetReadOffset(MemoryManager manager, ulong bufferAddress) public static uint GetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress)
{ {
return manager.Read<uint>(bufferAddress + ReadOffsetPosition); return manager.Read<uint>(bufferAddress + ReadOffsetPosition);
} }
public static uint GetWriteOffset(MemoryManager manager, ulong bufferAddress) public static uint GetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress)
{ {
return manager.Read<uint>(bufferAddress + WriteOffsetPosition); return manager.Read<uint>(bufferAddress + WriteOffsetPosition);
} }
public static void SetReadOffset(MemoryManager manager, ulong bufferAddress, uint value) public static void SetReadOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value)
{ {
manager.Write(bufferAddress + ReadOffsetPosition, value); manager.Write(bufferAddress + ReadOffsetPosition, value);
} }
public static void SetWriteOffset(MemoryManager manager, ulong bufferAddress, uint value) public static void SetWriteOffset(IVirtualMemoryManager manager, ulong bufferAddress, uint value)
{ {
manager.Write(bufferAddress + WriteOffsetPosition, value); manager.Write(bufferAddress + WriteOffsetPosition, value);
} }

View file

@ -8,6 +8,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" /> <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" /> <ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -31,7 +31,7 @@ using Ryujinx.Audio.Renderer.Server.Voice;
using Ryujinx.Audio.Renderer.Utils; using Ryujinx.Audio.Renderer.Utils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Memory;
using System; using System;
using System.Buffers; using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
@ -87,7 +87,7 @@ namespace Ryujinx.Audio.Renderer.Server
private Memory<byte> _performanceBuffer; private Memory<byte> _performanceBuffer;
public MemoryManager MemoryManager { get; private set; } public IVirtualMemoryManager MemoryManager { get; private set; }
private ulong _elapsedFrameCount; private ulong _elapsedFrameCount;
private ulong _renderingStartTick; private ulong _renderingStartTick;
@ -96,14 +96,14 @@ namespace Ryujinx.Audio.Renderer.Server
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent) public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
{ {
_manager = manager; _manager = manager;
_terminationEvent = new ManualResetEvent(false); _terminationEvent = new ManualResetEvent(false);
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp); _dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
_voiceContext = new VoiceContext(); _voiceContext = new VoiceContext();
_mixContext = new MixContext(); _mixContext = new MixContext();
_sinkContext = new SinkContext(); _sinkContext = new SinkContext();
_splitterContext = new SplitterContext(); _splitterContext = new SplitterContext();
_effectContext = new EffectContext(); _effectContext = new EffectContext();
_commandProcessingTimeEstimator = null; _commandProcessingTimeEstimator = null;
_systemEvent = systemEvent; _systemEvent = systemEvent;
@ -113,7 +113,7 @@ namespace Ryujinx.Audio.Renderer.Server
_sessionId = 0; _sessionId = 0;
} }
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, MemoryManager memoryManager) public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
{ {
if (!BehaviourContext.CheckValidRevision(parameter.Revision)) if (!BehaviourContext.CheckValidRevision(parameter.Revision))
{ {

View file

@ -19,7 +19,7 @@ using Ryujinx.Audio.Renderer.Dsp;
using Ryujinx.Audio.Renderer.Integration; using Ryujinx.Audio.Renderer.Integration;
using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Memory;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
@ -288,7 +288,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="workBufferSize">The guest work buffer size.</param> /// <param name="workBufferSize">The guest work buffer size.</param>
/// <param name="processHandle">The process handle of the application.</param> /// <param name="processHandle">The process handle of the application.</param>
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns> /// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, MemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle) public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle)
{ {
int sessionId = AcquireSessionId(); int sessionId = AcquireSessionId();
@ -321,6 +321,14 @@ namespace Ryujinx.Audio.Renderer.Server
{ {
if (disposing) if (disposing)
{ {
lock (_audioProcessorLock)
{
if (_isRunning)
{
StopLocked();
}
}
Processor.Dispose(); Processor.Dispose();
foreach (HardwareDevice device in OutputDevices) foreach (HardwareDevice device in OutputDevices)

View file

@ -1,4 +1,5 @@
using System; using Ryujinx.Memory;
using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@ -7,7 +8,7 @@ namespace Ryujinx.Cpu
{ {
public static class MemoryHelper public static class MemoryHelper
{ {
public static void FillWithZeros(MemoryManager memory, long position, int size) public static void FillWithZeros(IVirtualMemoryManager memory, long position, int size)
{ {
int size8 = size & ~(8 - 1); int size8 = size & ~(8 - 1);
@ -22,7 +23,7 @@ namespace Ryujinx.Cpu
} }
} }
public unsafe static T Read<T>(MemoryManager memory, long position) where T : struct public unsafe static T Read<T>(IVirtualMemoryManager memory, long position) where T : struct
{ {
long size = Marshal.SizeOf<T>(); long size = Marshal.SizeOf<T>();
@ -36,7 +37,7 @@ namespace Ryujinx.Cpu
} }
} }
public unsafe static void Write<T>(MemoryManager memory, long position, T value) where T : struct public unsafe static void Write<T>(IVirtualMemoryManager memory, long position, T value) where T : struct
{ {
long size = Marshal.SizeOf<T>(); long size = Marshal.SizeOf<T>();
@ -50,7 +51,7 @@ namespace Ryujinx.Cpu
memory.Write((ulong)position, data); memory.Write((ulong)position, data);
} }
public static string ReadAsciiString(MemoryManager memory, long position, long maxSize = -1) public static string ReadAsciiString(IVirtualMemoryManager memory, long position, long maxSize = -1)
{ {
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
{ {

View file

@ -13,7 +13,7 @@ namespace Ryujinx.Cpu
/// <summary> /// <summary>
/// Represents a CPU memory manager. /// Represents a CPU memory manager.
/// </summary> /// </summary>
public sealed class MemoryManager : IMemoryManager, IDisposable, IVirtualMemoryManager public sealed class MemoryManager : IMemoryManager, IVirtualMemoryManager, IDisposable
{ {
public const int PageBits = 12; public const int PageBits = 12;
public const int PageSize = 1 << PageBits; public const int PageSize = 1 << PageBits;
@ -468,6 +468,11 @@ namespace Ryujinx.Cpu
/// <returns>True if the entire range is mapped, false otherwise</returns> /// <returns>True if the entire range is mapped, false otherwise</returns>
public bool IsRangeMapped(ulong va, ulong size) public bool IsRangeMapped(ulong va, ulong size)
{ {
if (size == 0UL)
{
return true;
}
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask; ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
va &= ~(ulong)PageMask; va &= ~(ulong)PageMask;

View file

@ -1,4 +1,4 @@
using Ryujinx.Cpu; using Ryujinx.Memory;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;

View file

@ -1,5 +1,6 @@
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.Cpu.Tracking; using Ryujinx.Cpu.Tracking;
using Ryujinx.Memory;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -12,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
class PhysicalMemory class PhysicalMemory
{ {
public const int PageSize = Cpu.MemoryManager.PageSize; public const int PageSize = 0x1000;
private readonly Cpu.MemoryManager _cpuMemory; private readonly Cpu.MemoryManager _cpuMemory;

View file

@ -14,23 +14,26 @@ namespace Ryujinx.HLE.Exceptions
[Serializable] [Serializable]
internal class ServiceNotImplementedException : Exception internal class ServiceNotImplementedException : Exception
{ {
public IIpcService Service { get; }
public ServiceCtx Context { get; } public ServiceCtx Context { get; }
public IpcMessage Request { get; } public IpcMessage Request { get; }
public ServiceNotImplementedException(ServiceCtx context) public ServiceNotImplementedException(IIpcService service, ServiceCtx context)
: this(context, "The service call is not implemented.") : this(service, context, "The service call is not implemented.")
{ } { }
public ServiceNotImplementedException(ServiceCtx context, string message) public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message)
: base(message) : base(message)
{ {
Service = service;
Context = context; Context = context;
Request = context.Request; Request = context.Request;
} }
public ServiceNotImplementedException(ServiceCtx context, string message, Exception inner) public ServiceNotImplementedException(IIpcService service, ServiceCtx context, string message, Exception inner)
: base(message, inner) : base(message, inner)
{ {
Service = service;
Context = context; Context = context;
Request = context.Request; Request = context.Request;
} }
@ -59,17 +62,16 @@ namespace Ryujinx.HLE.Exceptions
if (callingType != null && callingMethod != null) if (callingType != null && callingMethod != null)
{ {
var ipcService = Context.Session.Service; var ipcCommands = Service.Commands;
var ipcCommands = ipcService.Commands;
// Find the handler for the method called // Find the handler for the method called
var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value as MethodBase == callingMethod); var ipcHandler = ipcCommands.FirstOrDefault(x => x.Value == callingMethod);
var ipcCommandId = ipcHandler.Key; var ipcCommandId = ipcHandler.Key;
var ipcMethod = ipcHandler.Value; var ipcMethod = ipcHandler.Value;
if (ipcMethod != null) if (ipcMethod != null)
{ {
sb.AppendLine($"Service Command: {ipcService.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})"); sb.AppendLine($"Service Command: {Service.GetType().FullName}: {ipcCommandId} ({ipcMethod.Name})");
sb.AppendLine(); sb.AppendLine();
} }
} }

View 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();
}
}

View 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));
}
}
}

View file

@ -120,11 +120,11 @@ namespace Ryujinx.HLE.HOS
iirsPageList.AddRange(iirsPa, IirsSize / KMemoryManager.PageSize); iirsPageList.AddRange(iirsPa, IirsSize / KMemoryManager.PageSize);
timePageList.AddRange(timePa, TimeSize / KMemoryManager.PageSize); timePageList.AddRange(timePa, TimeSize / KMemoryManager.PageSize);
HidSharedMem = new KSharedMemory(KernelContext, hidPageList, 0, 0, MemoryPermission.Read); HidSharedMem = new KSharedMemory(KernelContext, hidPageList, 0, 0, KMemoryPermission.Read);
FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, MemoryPermission.Read); FontSharedMem = new KSharedMemory(KernelContext, fontPageList, 0, 0, KMemoryPermission.Read);
IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, MemoryPermission.Read); IirsSharedMem = new KSharedMemory(KernelContext, iirsPageList, 0, 0, KMemoryPermission.Read);
KSharedMemory timeSharedMemory = new KSharedMemory(KernelContext, timePageList, 0, 0, MemoryPermission.Read); KSharedMemory timeSharedMemory = new KSharedMemory(KernelContext, timePageList, 0, 0, KMemoryPermission.Read);
TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timePa - DramMemoryMap.DramBase, TimeSize); TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timePa - DramMemoryMap.DramBase, TimeSize);
@ -134,8 +134,6 @@ namespace Ryujinx.HLE.HOS
Font = new SharedFontManager(device, fontPa - DramMemoryMap.DramBase); Font = new SharedFontManager(device, fontPa - DramMemoryMap.DramBase);
IUserInterface.InitializePort(this);
VsyncEvent = new KEvent(KernelContext); VsyncEvent = new KEvent(KernelContext);
DisplayResolutionChangeEvent = new KEvent(KernelContext); DisplayResolutionChangeEvent = new KEvent(KernelContext);
@ -224,6 +222,16 @@ namespace Ryujinx.HLE.HOS
AudioRendererManager.Initialize(writableEvents, devices); AudioRendererManager.Initialize(writableEvents, devices);
} }
public void InitializeServices()
{
IUserInterface sm = new IUserInterface(KernelContext);
// Wait until SM server thread is done with initialization,
// only then doing connections to SM is safe.
sm.Server.InitDone.WaitOne();
sm.Server.InitDone.Dispose();
}
public void LoadKip(string kipPath) public void LoadKip(string kipPath)
{ {
using IStorage kipFile = new LocalStorage(kipPath, FileAccess.Read); using IStorage kipFile = new LocalStorage(kipPath, FileAccess.Read);

View file

@ -84,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Ipc
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr); long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
if (rawDataSize != 0)
{
rawDataSize -= (int)pad0;
}
reader.BaseStream.Seek(pad0, SeekOrigin.Current); reader.BaseStream.Seek(pad0, SeekOrigin.Current);
int recvListCount = recvListFlags - 2; int recvListCount = recvListFlags - 2;
@ -107,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Ipc
} }
} }
public byte[] GetBytes(long cmdPtr) public byte[] GetBytes(long cmdPtr, ulong recvListAddr)
{ {
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
{ {
@ -131,7 +136,11 @@ namespace Ryujinx.HLE.HOS.Ipc
int dataLength = RawData?.Length ?? 0; int dataLength = RawData?.Length ?? 0;
int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length); dataLength = (dataLength + 3) & ~3;
int rawLength = dataLength;
int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length + PtrBuff.Count * 8);
// Apparently, padding after Raw Data is 16 bytes, however when there is // Apparently, padding after Raw Data is 16 bytes, however when there is
// padding before Raw Data too, we need to subtract the size of this padding. // padding before Raw Data too, we need to subtract the size of this padding.
@ -140,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Ipc
dataLength = (dataLength + pad0 + pad1) / 4; dataLength = (dataLength + pad0 + pad1) / 4;
word1 = dataLength & 0x3ff; word1 = (dataLength & 0x3ff) | (2 << 10);
if (HandleDesc != null) if (HandleDesc != null)
{ {
@ -151,14 +160,22 @@ namespace Ryujinx.HLE.HOS.Ipc
writer.Write(word1); writer.Write(word1);
writer.Write(handleData); writer.Write(handleData);
for (int index = 0; index < PtrBuff.Count; index++)
{
writer.Write(PtrBuff[index].GetWord0());
writer.Write(PtrBuff[index].GetWord1());
}
ms.Seek(pad0, SeekOrigin.Current); ms.Seek(pad0, SeekOrigin.Current);
if (RawData != null) if (RawData != null)
{ {
writer.Write(RawData); writer.Write(RawData);
ms.Seek(rawLength - RawData.Length, SeekOrigin.Current);
} }
writer.Write(new byte[pad1]); writer.Write(new byte[pad1]);
writer.Write(recvListAddr);
return ms.ToArray(); return ms.ToArray();
} }

View file

@ -8,6 +8,13 @@ namespace Ryujinx.HLE.HOS.Ipc
public int Index { get; private set; } public int Index { get; private set; }
public long Size { get; private set; } public long Size { get; private set; }
public IpcPtrBuffDesc(long position, int index, long size)
{
Position = position;
Index = index;
Size = size;
}
public IpcPtrBuffDesc(BinaryReader reader) public IpcPtrBuffDesc(BinaryReader reader)
{ {
long word0 = reader.ReadUInt32(); long word0 = reader.ReadUInt32();
@ -22,5 +29,25 @@ namespace Ryujinx.HLE.HOS.Ipc
Size = (ushort)(word0 >> 16); Size = (ushort)(word0 >> 16);
} }
public uint GetWord0()
{
uint word0;
word0 = (uint)((Position & 0x0f00000000) >> 20);
word0 |= (uint)((Position & 0x7000000000) >> 30);
word0 |= (uint)(Index & 0x03f) << 0;
word0 |= (uint)(Index & 0x1c0) << 3;
word0 |= (uint)Size << 16;
return word0;
}
public uint GetWord1()
{
return (uint)Position;
}
} }
} }

View file

@ -7,6 +7,12 @@ namespace Ryujinx.HLE.HOS.Ipc
public long Position { get; private set; } public long Position { get; private set; }
public long Size { get; private set; } public long Size { get; private set; }
public IpcRecvListBuffDesc(long position, long size)
{
Position = position;
Size = size;
}
public IpcRecvListBuffDesc(BinaryReader reader) public IpcRecvListBuffDesc(BinaryReader reader)
{ {
long value = reader.ReadInt64(); long value = reader.ReadInt64();

View 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();
}
}

View file

@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
copySize, copySize,
stateMask, stateMask,
stateMask, stateMask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
attributeMask, attributeMask,
MemoryAttribute.None, MemoryAttribute.None,
desc.ServerAddress); desc.ServerAddress);
@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
clientEndAddr - clientEndAddrTruncated, clientEndAddr - clientEndAddrTruncated,
stateMask, stateMask,
stateMask, stateMask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
attributeMask, attributeMask,
MemoryAttribute.None, MemoryAttribute.None,
serverEndAddrTruncated); serverEndAddrTruncated);

View file

@ -14,10 +14,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
public bool IsLight => _parent.IsLight; public bool IsLight => _parent.IsLight;
// TODO: Remove that, we need it for now to allow HLE
// SM implementation to work with the new IPC system.
public IpcService Service { get; set; }
public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context) public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
{ {
_maxSessions = maxSessions; _maxSessions = maxSessions;
@ -45,11 +41,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
KSession session = new KSession(KernelContext, this); KSession session = new KSession(KernelContext, this);
if (Service != null)
{
session.ClientSession.Service = Service;
}
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession); KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
if (result != KernelResult.Success) if (result != KernelResult.Success)

View file

@ -16,10 +16,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
public KClientPort ParentPort { get; } public KClientPort ParentPort { get; }
// TODO: Remove that, we need it for now to allow HLE
// services implementation to work with the new IPC system.
public IpcService Service { get; set; }
public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context) public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context)
{ {
_parent = parent; _parent = parent;
@ -84,11 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
{ {
_parent.DisconnectClient(); _parent.DisconnectClient();
_parent.DecrementReferenceCount(); _parent.DecrementReferenceCount();
if (Service is IDisposable disposableObj)
{
disposableObj.Dispose();
}
} }
} }
} }

View file

@ -430,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
descriptor.BufferAddress, descriptor.BufferAddress,
MemoryState.IsPoolAllocated, MemoryState.IsPoolAllocated,
MemoryState.IsPoolAllocated, MemoryState.IsPoolAllocated,
MemoryPermission.Read, KMemoryPermission.Read,
MemoryAttribute.Uncached, MemoryAttribute.Uncached,
MemoryAttribute.None); MemoryAttribute.None);
@ -473,9 +473,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
bool notReceiveDesc = isSendDesc || isExchangeDesc; bool notReceiveDesc = isSendDesc || isExchangeDesc;
bool isReceiveDesc = !notReceiveDesc; bool isReceiveDesc = !notReceiveDesc;
MemoryPermission permission = index >= clientHeader.SendBuffersCount KMemoryPermission permission = index >= clientHeader.SendBuffersCount
? MemoryPermission.ReadAndWrite ? KMemoryPermission.ReadAndWrite
: MemoryPermission.Read; : KMemoryPermission.Read;
uint sizeHigh4 = (descWord2 >> 24) & 0xf; uint sizeHigh4 = (descWord2 >> 24) & 0xf;
@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (serverMsg.IsCustom || clientMsg.IsCustom) if (serverMsg.IsCustom || clientMsg.IsCustom)
{ {
MemoryPermission permission = clientMsg.IsCustom KMemoryPermission permission = clientMsg.IsCustom
? MemoryPermission.None ? KMemoryPermission.None
: MemoryPermission.Read; : KMemoryPermission.Read;
clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess( clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
copyDst, copyDst,
@ -795,7 +795,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
descriptor.BufferSize, descriptor.BufferSize,
MemoryState.IsPoolAllocated, MemoryState.IsPoolAllocated,
MemoryState.IsPoolAllocated, MemoryState.IsPoolAllocated,
MemoryPermission.Read, KMemoryPermission.Read,
MemoryAttribute.Uncached, MemoryAttribute.Uncached,
MemoryAttribute.None, MemoryAttribute.None,
descriptor.BufferAddress); descriptor.BufferAddress);
@ -849,9 +849,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (serverMsg.IsCustom || clientMsg.IsCustom) if (serverMsg.IsCustom || clientMsg.IsCustom)
{ {
MemoryPermission permission = clientMsg.IsCustom KMemoryPermission permission = clientMsg.IsCustom
? MemoryPermission.None ? KMemoryPermission.None
: MemoryPermission.Read; : KMemoryPermission.Read;
clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess( clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
copyDst, copyDst,
@ -898,11 +898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return new MessageHeader(word0, word1, word2); return new MessageHeader(word0, word1, word2);
} }
private KernelResult GetCopyObjectHandle( private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
KThread srcThread,
KProcess dstProcess,
int srcHandle,
out int dstHandle)
{ {
dstHandle = 0; dstHandle = 0;
@ -933,11 +929,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
} }
} }
private KernelResult GetMoveObjectHandle( private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
KProcess srcProcess,
KProcess dstProcess,
int srcHandle,
out int dstHandle)
{ {
dstHandle = 0; dstHandle = 0;

View file

@ -4,7 +4,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Ipc namespace Ryujinx.HLE.HOS.Kernel.Ipc
{ {
class KSession : KAutoObject, IDisposable class KSession : KAutoObject
{ {
public KServerSession ServerSession { get; } public KServerSession ServerSession { get; }
public KClientSession ClientSession { get; } public KClientSession ClientSession { get; }
@ -37,19 +37,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
} }
} }
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing && ClientSession.Service is IDisposable disposableService)
{
disposableService.Dispose();
}
}
protected override void Destroy() protected override void Destroy()
{ {
if (_hasBeenInitialized) if (_hasBeenInitialized)

View file

@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
Device = device; Device = device;
Memory = memory; Memory = memory;
Syscall = new Syscall(device, this); Syscall = new Syscall(this);
SyscallHandler = new SyscallHandler(this); SyscallHandler = new SyscallHandler(this);

View 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;
}
}
}

View file

@ -8,9 +8,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong PagesCount { get; private set; } public ulong PagesCount { get; private set; }
public MemoryState State { get; private set; } public MemoryState State { get; private set; }
public MemoryPermission Permission { get; private set; } public KMemoryPermission Permission { get; private set; }
public MemoryAttribute Attribute { get; private set; } public MemoryAttribute Attribute { get; private set; }
public MemoryPermission SourcePermission { get; private set; } public KMemoryPermission SourcePermission { get; private set; }
public int IpcRefCount { get; private set; } public int IpcRefCount { get; private set; }
public int DeviceRefCount { get; private set; } public int DeviceRefCount { get; private set; }
@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong baseAddress, ulong baseAddress,
ulong pagesCount, ulong pagesCount,
MemoryState state, MemoryState state,
MemoryPermission permission, KMemoryPermission permission,
MemoryAttribute attribute, MemoryAttribute attribute,
int ipcRefCount = 0, int ipcRefCount = 0,
int deviceRefCount = 0) int deviceRefCount = 0)
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
DeviceRefCount = deviceRefCount; DeviceRefCount = deviceRefCount;
} }
public void SetState(MemoryPermission permission, MemoryState state, MemoryAttribute attribute) public void SetState(KMemoryPermission permission, MemoryState state, MemoryAttribute attribute)
{ {
Permission = permission; Permission = permission;
State = state; State = state;
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Attribute |= attribute; Attribute |= attribute;
} }
public void SetIpcMappingPermission(MemoryPermission newPermission) public void SetIpcMappingPermission(KMemoryPermission newPermission)
{ {
int oldIpcRefCount = IpcRefCount++; int oldIpcRefCount = IpcRefCount++;
@ -54,8 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
SourcePermission = Permission; SourcePermission = Permission;
Permission &= ~MemoryPermission.ReadAndWrite; Permission &= ~KMemoryPermission.ReadAndWrite;
Permission |= MemoryPermission.ReadAndWrite & newPermission; Permission |= KMemoryPermission.ReadAndWrite & newPermission;
} }
Attribute |= MemoryAttribute.IpcMapped; Attribute |= MemoryAttribute.IpcMapped;
@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
Permission = SourcePermission; Permission = SourcePermission;
SourcePermission = MemoryPermission.None; SourcePermission = KMemoryPermission.None;
Attribute &= ~MemoryAttribute.IpcMapped; Attribute &= ~MemoryAttribute.IpcMapped;
} }

View file

@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong Size { get; } public ulong Size { get; }
public MemoryState State { get; } public MemoryState State { get; }
public MemoryPermission Permission { get; } public KMemoryPermission Permission { get; }
public MemoryAttribute Attribute { get; } public MemoryAttribute Attribute { get; }
public MemoryPermission SourcePermission { get; } public KMemoryPermission SourcePermission { get; }
public int IpcRefCount { get; } public int IpcRefCount { get; }
public int DeviceRefCount { get; } public int DeviceRefCount { get; }
@ -17,9 +17,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address, ulong address,
ulong size, ulong size,
MemoryState state, MemoryState state,
MemoryPermission permission, KMemoryPermission permission,
MemoryAttribute attribute, MemoryAttribute attribute,
MemoryPermission sourcePermission, KMemoryPermission sourcePermission,
int ipcRefCount, int ipcRefCount,
int deviceRefCount) int deviceRefCount)
{ {

View file

@ -1,9 +1,10 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
namespace Ryujinx.HLE.HOS.Kernel.Memory namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
@ -27,11 +28,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
// needs to be split in 2, plus one block that will be the new one inserted. // needs to be split in 2, plus one block that will be the new one inserted.
private const int MaxBlocksNeededForInsertion = 2; private const int MaxBlocksNeededForInsertion = 2;
private LinkedList<KMemoryBlock> _blocks; private readonly LinkedList<KMemoryBlock> _blocks;
private MemoryManager _cpuMemory; private readonly IVirtualMemoryManager _cpuMemory;
private KernelContext _context; private readonly KernelContext _context;
public ulong AddrSpaceStart { get; private set; } public ulong AddrSpaceStart { get; private set; }
public ulong AddrSpaceEnd { get; private set; } public ulong AddrSpaceEnd { get; private set; }
@ -73,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MersenneTwister _randomNumberGenerator; private MersenneTwister _randomNumberGenerator;
public KMemoryManager(KernelContext context, MemoryManager cpuMemory) public KMemoryManager(KernelContext context, IVirtualMemoryManager cpuMemory)
{ {
_context = context; _context = context;
_cpuMemory = cpuMemory; _cpuMemory = cpuMemory;
@ -352,7 +353,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
addrSpaceStart, addrSpaceStart,
addrSpacePagesCount, addrSpacePagesCount,
MemoryState.Unmapped, MemoryState.Unmapped,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.None)); MemoryAttribute.None));
return KernelResult.Success; return KernelResult.Success;
@ -362,13 +363,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address, ulong address,
KPageList pageList, KPageList pageList,
MemoryState state, MemoryState state,
MemoryPermission permission) KMemoryPermission permission)
{ {
ulong pagesCount = pageList.GetPagesCount(); ulong pagesCount = pageList.GetPagesCount();
ulong size = pagesCount * PageSize; ulong size = pagesCount * PageSize;
if (!ValidateRegionForState(address, size, state)) if (!CanContain(address, size, state))
{ {
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
@ -437,8 +438,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
stateExpected, stateExpected,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -467,13 +468,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
} }
public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission) public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission)
{ {
// TODO. // TODO.
return KernelResult.Success; return KernelResult.Success;
} }
public KernelResult MapIoMemory(long address, long size, MemoryPermission permission) public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
{ {
// TODO. // TODO.
return KernelResult.Success; return KernelResult.Success;
@ -487,7 +488,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong regionStart, ulong regionStart,
ulong regionPagesCount, ulong regionPagesCount,
MemoryState state, MemoryState state,
MemoryPermission permission, KMemoryPermission permission,
out ulong address) out ulong address)
{ {
address = 0; address = 0;
@ -496,7 +497,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong regionEndAddr = regionStart + regionSize; ulong regionEndAddr = regionStart + regionSize;
if (!ValidateRegionForState(regionStart, regionSize, state)) if (!CanContain(regionStart, regionSize, state))
{ {
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
@ -547,11 +548,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address, ulong address,
ulong pagesCount, ulong pagesCount,
MemoryState state, MemoryState state,
MemoryPermission permission) KMemoryPermission permission)
{ {
ulong size = pagesCount * PageSize; ulong size = pagesCount * PageSize;
if (!ValidateRegionForState(address, size, state)) if (!CanContain(address, size, state))
{ {
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
@ -596,13 +597,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
MemoryState.Heap, MemoryState.Heap,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out MemoryState state, out MemoryState state,
out MemoryPermission permission, out KMemoryPermission permission,
out _); out _);
success &= IsUnmapped(dst, size); success &= IsUnmapped(dst, size);
@ -618,14 +619,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddVaRangeToPageList(pageList, src, pagesCount); AddVaRangeToPageList(pageList, src, pagesCount);
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None); KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
return result; return result;
} }
result = MapPages(dst, pageList, MemoryPermission.None); result = MapPages(dst, pageList, KMemoryPermission.None);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -634,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result; return result;
} }
InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed); InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic); InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
return KernelResult.Success; return KernelResult.Success;
@ -657,8 +658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
MemoryState.Heap, MemoryState.Heap,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.Borrowed, MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -671,8 +672,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
PageSize, PageSize,
MemoryState.UnmapProcessCodeMemoryAllowed, MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryState.UnmapProcessCodeMemoryAllowed, MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -685,8 +686,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
state, state,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None); MemoryAttribute.None);
@ -707,7 +708,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
InsertBlock(dst, pagesCount, MemoryState.Unmapped); InsertBlock(dst, pagesCount, MemoryState.Unmapped);
InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
return KernelResult.Success; return KernelResult.Success;
} }
@ -788,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_currentHeapAddr, _currentHeapAddr,
pagesCount, pagesCount,
pageList, pageList,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryOperation.MapVa); MemoryOperation.MapVa);
if (result != KernelResult.Success) if (result != KernelResult.Success)
@ -798,7 +799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result; return result;
} }
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
} }
else else
{ {
@ -816,8 +817,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
sizeDelta, sizeDelta,
MemoryState.Mask, MemoryState.Mask,
MemoryState.Heap, MemoryState.Heap,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -886,13 +887,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.AttributeChangeAllowed, MemoryState.AttributeChangeAllowed,
MemoryState.AttributeChangeAllowed, MemoryState.AttributeChangeAllowed,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.BorrowedAndIpcMapped, MemoryAttribute.BorrowedAndIpcMapped,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.DeviceMappedAndUncached, MemoryAttribute.DeviceMappedAndUncached,
out MemoryState state, out MemoryState state,
out MemoryPermission permission, out KMemoryPermission permission,
out MemoryAttribute attribute)) out MemoryAttribute attribute))
{ {
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
@ -932,9 +933,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddrSpaceEnd, AddrSpaceEnd,
~AddrSpaceEnd + 1, ~AddrSpaceEnd + 1,
MemoryState.Reserved, MemoryState.Reserved,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.None, MemoryAttribute.None,
MemoryPermission.None, KMemoryPermission.None,
0, 0,
0); 0);
} }
@ -951,8 +952,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.MapAllowed, MemoryState.MapAllowed,
MemoryState.MapAllowed, MemoryState.MapAllowed,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -975,18 +976,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddVaRangeToPageList(pageList, src, pagesCount); AddVaRangeToPageList(pageList, src, pagesCount);
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None); KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
return result; return result;
} }
result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite); result = MapPages(dst, pageList, KMemoryPermission.ReadAndWrite);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
if (MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite) != KernelResult.Success) if (MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite) != KernelResult.Success)
{ {
throw new InvalidOperationException("Unexpected failure reverting memory permission."); throw new InvalidOperationException("Unexpected failure reverting memory permission.");
} }
@ -994,8 +995,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result; return result;
} }
InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed); InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite); InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
return KernelResult.Success; return KernelResult.Success;
} }
@ -1017,8 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
stateExpected, stateExpected,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -1058,8 +1059,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.MapAllowed, MemoryState.MapAllowed,
MemoryState.MapAllowed, MemoryState.MapAllowed,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.Borrowed, MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -1072,13 +1073,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
MemoryState.Stack, MemoryState.Stack,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out _, out _,
out MemoryPermission dstPermission, out KMemoryPermission dstPermission,
out _); out _);
if (success) if (success)
@ -1108,7 +1109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result; return result;
} }
result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite); result = MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -1117,7 +1118,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result; return result;
} }
InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite); InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
InsertBlock(dst, pagesCount, MemoryState.Unmapped); InsertBlock(dst, pagesCount, MemoryState.Unmapped);
return KernelResult.Success; return KernelResult.Success;
@ -1129,7 +1130,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
} }
public KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission) public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{ {
lock (_blocks) lock (_blocks)
{ {
@ -1138,20 +1139,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.ProcessPermissionChangeAllowed, MemoryState.ProcessPermissionChangeAllowed,
MemoryState.ProcessPermissionChangeAllowed, MemoryState.ProcessPermissionChangeAllowed,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState, out MemoryState oldState,
out MemoryPermission oldPermission, out KMemoryPermission oldPermission,
out _)) out _))
{ {
MemoryState newState = oldState; MemoryState newState = oldState;
// If writing into the code region is allowed, then we need // If writing into the code region is allowed, then we need
// to change it to mutable. // to change it to mutable.
if ((permission & MemoryPermission.Write) != 0) if ((permission & KMemoryPermission.Write) != 0)
{ {
if (oldState == MemoryState.CodeStatic) if (oldState == MemoryState.CodeStatic)
{ {
@ -1176,7 +1177,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize; ulong pagesCount = size / PageSize;
MemoryOperation operation = (permission & MemoryPermission.Execute) != 0 MemoryOperation operation = (permission & KMemoryPermission.Execute) != 0
? MemoryOperation.ChangePermsAndAttributes ? MemoryOperation.ChangePermsAndAttributes
: MemoryOperation.ChangePermRw; : MemoryOperation.ChangePermRw;
@ -1270,10 +1271,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
address, address,
pagesCount, pagesCount,
MemoryState.Unmapped, MemoryState.Unmapped,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.None, MemoryAttribute.None,
MemoryState.Heap, MemoryState.Heap,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.None); MemoryAttribute.None);
} }
@ -1410,7 +1411,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesCount, pagesCount,
srcPa, srcPa,
true, true,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryOperation.MapPa); MemoryOperation.MapPa);
dstVa += pagesCount * PageSize; dstVa += pagesCount * PageSize;
@ -1428,7 +1429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong src, ulong src,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permission, KMemoryPermission permission,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected) MemoryAttribute attributeExpected)
{ {
@ -1450,7 +1451,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size, ulong size,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permission, KMemoryPermission permission,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected, MemoryAttribute attributeExpected,
ulong src) ulong src)
@ -1474,7 +1475,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong serverAddress, ulong serverAddress,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permission, KMemoryPermission permission,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected, MemoryAttribute attributeExpected,
bool toServer) bool toServer)
@ -1529,7 +1530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size, ulong size,
ulong src, ulong src,
KMemoryManager sourceMemMgr, KMemoryManager sourceMemMgr,
MemoryPermission permission, KMemoryPermission permission,
MemoryState state, MemoryState state,
bool copyData, bool copyData,
out ulong dst) out ulong dst)
@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private KernelResult GetPagesForMappingIntoAnotherProcess( private KernelResult GetPagesForMappingIntoAnotherProcess(
ulong address, ulong address,
ulong size, ulong size,
MemoryPermission permission, KMemoryPermission permission,
MemoryState state, MemoryState state,
bool copyData, bool copyData,
bool aslrDisabled, bool aslrDisabled,
@ -1600,9 +1601,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
default: return KernelResult.InvalidCombination; default: return KernelResult.InvalidCombination;
} }
MemoryPermission permissionMask = permission == MemoryPermission.ReadAndWrite KMemoryPermission permissionMask = permission == KMemoryPermission.ReadAndWrite
? MemoryPermission.None ? KMemoryPermission.None
: MemoryPermission.Read; : KMemoryPermission.Read;
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached; MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
@ -1634,7 +1635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited)) foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited))
{ {
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0) if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
{ {
ulong blockAddress = GetAddrInRange(info, addressRounded); ulong blockAddress = GetAddrInRange(info, addressRounded);
ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited); ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited);
@ -1661,7 +1662,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (addressRounded < endAddrTruncated) if (addressRounded < endAddrTruncated)
{ {
foreach (KMemoryInfo info in IterateOverRange(addressTruncated, endAddrRounded)) foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrTruncated))
{ {
// Check if the block state matches what we expect. // Check if the block state matches what we expect.
if ((info.State & stateMask) != stateMask || if ((info.State & stateMask) != stateMask ||
@ -1678,7 +1679,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong blockPagesCount = blockSize / PageSize; ulong blockPagesCount = blockSize / PageSize;
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0) if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
{ {
result = DoMmuOperation( result = DoMmuOperation(
blockAddress, blockAddress,
@ -1784,7 +1785,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
ulong unusedSizeBefore = address - addressTruncated; ulong unusedSizeBefore = address - addressTruncated;
_context.Memory.ZeroFill(dstFirstPagePa, unusedSizeBefore); _context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore);
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size; ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
@ -1803,7 +1804,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (unusedSizeAfter != 0) if (unusedSizeAfter != 0)
{ {
_context.Memory.ZeroFill(firstPageFillAddress, unusedSizeAfter); _context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter);
} }
if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success) if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success)
@ -1865,7 +1866,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
unusedSizeAfter = PageSize; unusedSizeAfter = PageSize;
} }
_context.Memory.ZeroFill(lastPageFillAddr, unusedSizeAfter); _context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter);
if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success) if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success)
{ {
@ -1897,7 +1898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private KernelResult MapPagesFromAnotherProcess( private KernelResult MapPagesFromAnotherProcess(
ulong size, ulong size,
ulong address, ulong address,
MemoryPermission permission, KMemoryPermission permission,
MemoryState state, MemoryState state,
KPageList pageList, KPageList pageList,
out ulong dst) out ulong dst)
@ -1975,8 +1976,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
state, state,
MemoryPermission.Read, KMemoryPermission.Read,
MemoryPermission.Read, KMemoryPermission.Read,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -1996,14 +1997,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize; ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
KernelResult result = DoMmuOperation(
addressTruncated,
pagesCount,
0,
false,
MemoryPermission.None,
MemoryOperation.Unmap);
// Free pages we had to create on-demand, if any of the buffer was not page aligned. // Free pages we had to create on-demand, if any of the buffer was not page aligned.
// Real kernel has page ref counting, so this is done as part of the unmap operation. // Real kernel has page ref counting, so this is done as part of the unmap operation.
if (addressTruncated != addressRounded) if (addressTruncated != addressRounded)
@ -2016,6 +2009,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated)); FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated));
} }
KernelResult result = DoMmuOperation(
addressTruncated,
pagesCount,
0,
false,
KMemoryPermission.None,
MemoryOperation.Unmap);
if (result == KernelResult.Success) if (result == KernelResult.Success)
{ {
InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped); InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
@ -2037,7 +2038,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong addressRounded = BitUtils.AlignUp (address, PageSize); ulong addressRounded = BitUtils.AlignUp (address, PageSize);
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize); ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
ulong pagesCount = (endAddrTruncated - addressRounded) / PageSize; ulong pagesCount = addressRounded < endAddrTruncated ? (endAddrTruncated - addressRounded) / PageSize : 0;
if (pagesCount == 0)
{
return KernelResult.Success;
}
MemoryState stateMask; MemoryState stateMask;
@ -2111,23 +2117,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.IpcBufferAllowed, MemoryState.IpcBufferAllowed,
MemoryState.IpcBufferAllowed, MemoryState.IpcBufferAllowed,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Borrowed); MemoryAttribute.Borrowed);
} }
public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, MemoryPermission permission) public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
{ {
return SetAttributesAndChangePermission( return SetAttributesAndChangePermission(
address, address,
size, size,
MemoryState.TransferMemoryAllowed, MemoryState.TransferMemoryAllowed,
MemoryState.TransferMemoryAllowed, MemoryState.TransferMemoryAllowed,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
permission, permission,
@ -2140,11 +2146,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size, ulong size,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permissionMask, KMemoryPermission permissionMask,
MemoryPermission permissionExpected, KMemoryPermission permissionExpected,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected, MemoryAttribute attributeExpected,
MemoryPermission newPermission, KMemoryPermission newPermission,
MemoryAttribute attributeSetMask, MemoryAttribute attributeSetMask,
KPageList pageList = null) KPageList pageList = null)
{ {
@ -2166,7 +2172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
attributeExpected, attributeExpected,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState, out MemoryState oldState,
out MemoryPermission oldPermission, out KMemoryPermission oldPermission,
out MemoryAttribute oldAttribute)) out MemoryAttribute oldAttribute))
{ {
ulong pagesCount = size / PageSize; ulong pagesCount = size / PageSize;
@ -2181,7 +2187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource; return KernelResult.OutOfResource;
} }
if (newPermission == MemoryPermission.None) if (newPermission == KMemoryPermission.None)
{ {
newPermission = oldPermission; newPermission = oldPermission;
} }
@ -2222,11 +2228,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.IpcBufferAllowed, MemoryState.IpcBufferAllowed,
MemoryState.IpcBufferAllowed, MemoryState.IpcBufferAllowed,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.Borrowed, MemoryAttribute.Borrowed,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed); MemoryAttribute.Borrowed);
} }
@ -2237,11 +2243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.TransferMemoryAllowed, MemoryState.TransferMemoryAllowed,
MemoryState.TransferMemoryAllowed, MemoryState.TransferMemoryAllowed,
MemoryPermission.None, KMemoryPermission.None,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.Borrowed, MemoryAttribute.Borrowed,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed, MemoryAttribute.Borrowed,
pageList); pageList);
} }
@ -2251,11 +2257,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size, ulong size,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permissionMask, KMemoryPermission permissionMask,
MemoryPermission permissionExpected, KMemoryPermission permissionExpected,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected, MemoryAttribute attributeExpected,
MemoryPermission newPermission, KMemoryPermission newPermission,
MemoryAttribute attributeClearMask, MemoryAttribute attributeClearMask,
KPageList pageList = null) KPageList pageList = null)
{ {
@ -2277,7 +2283,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
attributeExpected, attributeExpected,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState, out MemoryState oldState,
out MemoryPermission oldPermission, out KMemoryPermission oldPermission,
out MemoryAttribute oldAttribute)) out MemoryAttribute oldAttribute))
{ {
ulong pagesCount = size / PageSize; ulong pagesCount = size / PageSize;
@ -2299,7 +2305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource; return KernelResult.OutOfResource;
} }
if (newPermission == MemoryPermission.None) if (newPermission == KMemoryPermission.None)
{ {
newPermission = oldPermission; newPermission = oldPermission;
} }
@ -2385,8 +2391,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size, size,
MemoryState.Mask, MemoryState.Mask,
MemoryState.Unmapped, MemoryState.Unmapped,
MemoryPermission.Mask, KMemoryPermission.Mask,
MemoryPermission.None, KMemoryPermission.None,
MemoryAttribute.Mask, MemoryAttribute.Mask,
MemoryAttribute.None, MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped, MemoryAttribute.IpcAndDeviceMapped,
@ -2400,13 +2406,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size, ulong size,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permissionMask, KMemoryPermission permissionMask,
MemoryPermission permissionExpected, KMemoryPermission permissionExpected,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected, MemoryAttribute attributeExpected,
MemoryAttribute attributeIgnoreMask, MemoryAttribute attributeIgnoreMask,
out MemoryState outState, out MemoryState outState,
out MemoryPermission outPermission, out KMemoryPermission outPermission,
out MemoryAttribute outAttribute) out MemoryAttribute outAttribute)
{ {
ulong endAddr = address + size; ulong endAddr = address + size;
@ -2416,7 +2422,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KMemoryInfo info = node.Value.GetInfo(); KMemoryInfo info = node.Value.GetInfo();
MemoryState firstState = info.State; MemoryState firstState = info.State;
MemoryPermission firstPermission = info.Permission; KMemoryPermission firstPermission = info.Permission;
MemoryAttribute firstAttribute = info.Attribute; MemoryAttribute firstAttribute = info.Attribute;
do do
@ -2432,7 +2438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
(firstPermission & permissionMask) != permissionExpected) (firstPermission & permissionMask) != permissionExpected)
{ {
outState = MemoryState.Unmapped; outState = MemoryState.Unmapped;
outPermission = MemoryPermission.None; outPermission = KMemoryPermission.None;
outAttribute = MemoryAttribute.None; outAttribute = MemoryAttribute.None;
return false; return false;
@ -2452,8 +2458,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size, ulong size,
MemoryState stateMask, MemoryState stateMask,
MemoryState stateExpected, MemoryState stateExpected,
MemoryPermission permissionMask, KMemoryPermission permissionMask,
MemoryPermission permissionExpected, KMemoryPermission permissionExpected,
MemoryAttribute attributeMask, MemoryAttribute attributeMask,
MemoryAttribute attributeExpected) MemoryAttribute attributeExpected)
{ {
@ -2490,10 +2496,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong baseAddress, ulong baseAddress,
ulong pagesCount, ulong pagesCount,
MemoryState oldState, MemoryState oldState,
MemoryPermission oldPermission, KMemoryPermission oldPermission,
MemoryAttribute oldAttribute, MemoryAttribute oldAttribute,
MemoryState newState, MemoryState newState,
MemoryPermission newPermission, KMemoryPermission newPermission,
MemoryAttribute newAttribute) MemoryAttribute newAttribute)
{ {
// Insert new block on the list only on areas where the state // Insert new block on the list only on areas where the state
@ -2553,13 +2559,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
_blockAllocator.Count += _blocks.Count - oldCount; _blockAllocator.Count += _blocks.Count - oldCount;
ValidateInternalState();
} }
private void InsertBlock( private void InsertBlock(
ulong baseAddress, ulong baseAddress,
ulong pagesCount, ulong pagesCount,
MemoryState state, MemoryState state,
MemoryPermission permission = MemoryPermission.None, KMemoryPermission permission = KMemoryPermission.None,
MemoryAttribute attribute = MemoryAttribute.None) MemoryAttribute attribute = MemoryAttribute.None)
{ {
// Inserts new block at the list, replacing and splitting // Inserts new block at the list, replacing and splitting
@ -2605,25 +2613,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
_blockAllocator.Count += _blocks.Count - oldCount; _blockAllocator.Count += _blocks.Count - oldCount;
ValidateInternalState();
} }
private static void SetIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission) private static void SetIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
{ {
block.SetIpcMappingPermission(permission); block.SetIpcMappingPermission(permission);
} }
private static void RestoreIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission) private static void RestoreIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
{ {
block.RestoreIpcMappingPermission(); block.RestoreIpcMappingPermission();
} }
private delegate void BlockMutator(KMemoryBlock block, MemoryPermission newPerm); private delegate void BlockMutator(KMemoryBlock block, KMemoryPermission newPerm);
private void InsertBlock( private void InsertBlock(
ulong baseAddress, ulong baseAddress,
ulong pagesCount, ulong pagesCount,
BlockMutator blockMutate, BlockMutator blockMutate,
MemoryPermission permission = MemoryPermission.None) KMemoryPermission permission = KMemoryPermission.None)
{ {
// Inserts new block at the list, replacing and splitting // Inserts new block at the list, replacing and splitting
// existing blocks as needed, then calling the callback // existing blocks as needed, then calling the callback
@ -2671,6 +2681,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
_blockAllocator.Count += _blocks.Count - oldCount; _blockAllocator.Count += _blocks.Count - oldCount;
ValidateInternalState();
}
[Conditional("DEBUG")]
private void ValidateInternalState()
{
ulong expectedAddress = 0;
LinkedListNode<KMemoryBlock> node = _blocks.First;
while (node != null)
{
LinkedListNode<KMemoryBlock> newNode = node;
KMemoryBlock currBlock = node.Value;
Debug.Assert(currBlock.BaseAddress == expectedAddress);
expectedAddress = currBlock.BaseAddress + currBlock.PagesCount * PageSize;
node = newNode.Next;
}
Debug.Assert(expectedAddress == AddrSpaceEnd);
} }
private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node) private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node)
@ -2876,13 +2911,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return null; return null;
} }
private bool ValidateRegionForState(ulong address, ulong size, MemoryState state) public bool CanContain(ulong address, ulong size, MemoryState state)
{ {
ulong endAddr = address + size; ulong endAddr = address + size;
ulong regionBaseAddr = GetBaseAddrForState(state); ulong regionBaseAddr = GetBaseAddress(state);
ulong regionEndAddr = regionBaseAddr + GetSize(state);
ulong regionEndAddr = regionBaseAddr + GetSizeForState(state);
bool InsideRegion() bool InsideRegion()
{ {
@ -2891,17 +2925,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
endAddr - 1 <= regionEndAddr - 1; endAddr - 1 <= regionEndAddr - 1;
} }
bool OutsideHeapRegion() bool OutsideHeapRegion() => endAddr <= HeapRegionStart || address >= HeapRegionEnd;
{ bool OutsideAliasRegion() => endAddr <= AliasRegionStart || address >= AliasRegionEnd;
return endAddr <= HeapRegionStart ||
address >= HeapRegionEnd;
}
bool OutsideMapRegion()
{
return endAddr <= AliasRegionStart ||
address >= AliasRegionEnd;
}
switch (state) switch (state)
{ {
@ -2919,10 +2944,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
case MemoryState.ProcessMemory: case MemoryState.ProcessMemory:
case MemoryState.CodeReadOnly: case MemoryState.CodeReadOnly:
case MemoryState.CodeWritable: case MemoryState.CodeWritable:
return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion(); return InsideRegion() && OutsideHeapRegion() && OutsideAliasRegion();
case MemoryState.Heap: case MemoryState.Heap:
return InsideRegion() && OutsideMapRegion(); return InsideRegion() && OutsideAliasRegion();
case MemoryState.IpcBuffer0: case MemoryState.IpcBuffer0:
case MemoryState.IpcBuffer1: case MemoryState.IpcBuffer1:
@ -2936,7 +2961,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
throw new ArgumentException($"Invalid state value \"{state}\"."); throw new ArgumentException($"Invalid state value \"{state}\".");
} }
private ulong GetBaseAddrForState(MemoryState state) private ulong GetBaseAddress(MemoryState state)
{ {
switch (state) switch (state)
{ {
@ -2975,7 +3000,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
throw new ArgumentException($"Invalid state value \"{state}\"."); throw new ArgumentException($"Invalid state value \"{state}\".");
} }
private ulong GetSizeForState(MemoryState state) private ulong GetSize(MemoryState state)
{ {
switch (state) switch (state)
{ {
@ -3050,7 +3075,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
} }
} }
private KernelResult MapPages(ulong address, KPageList pageList, MemoryPermission permission) private KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission)
{ {
ulong currAddr = address; ulong currAddr = address;
@ -3090,11 +3115,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesCount, pagesCount,
0, 0,
false, false,
MemoryPermission.None, KMemoryPermission.None,
MemoryOperation.Unmap); MemoryOperation.Unmap);
} }
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission) private KernelResult MmuChangePermission(ulong address, ulong pagesCount, KMemoryPermission permission)
{ {
return DoMmuOperation( return DoMmuOperation(
address, address,
@ -3110,7 +3135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount, ulong pagesCount,
ulong srcPa, ulong srcPa,
bool map, bool map,
MemoryPermission permission, KMemoryPermission permission,
MemoryOperation operation) MemoryOperation operation)
{ {
if (map != (operation == MemoryOperation.MapPa)) if (map != (operation == MemoryOperation.MapPa))
@ -3171,7 +3196,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address, ulong address,
ulong pagesCount, ulong pagesCount,
KPageList pageList, KPageList pageList,
MemoryPermission permission, KMemoryPermission permission,
MemoryOperation operation) MemoryOperation operation)
{ {
if (operation != MemoryOperation.MapVa) if (operation != MemoryOperation.MapVa)

View file

@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private readonly long _ownerPid; private readonly long _ownerPid;
private readonly MemoryPermission _ownerPermission; private readonly KMemoryPermission _ownerPermission;
private readonly MemoryPermission _userPermission; private readonly KMemoryPermission _userPermission;
public KSharedMemory( public KSharedMemory(
KernelContext context, KernelContext context,
KPageList pageList, KPageList pageList,
long ownerPid, long ownerPid,
MemoryPermission ownerPermission, KMemoryPermission ownerPermission,
MemoryPermission userPermission) : base(context) KMemoryPermission userPermission) : base(context)
{ {
_pageList = pageList; _pageList = pageList;
_ownerPid = ownerPid; _ownerPid = ownerPid;
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address, ulong address,
ulong size, ulong size,
KProcess process, KProcess process,
MemoryPermission permission) KMemoryPermission permission)
{ {
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize); ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.InvalidSize; return KernelResult.InvalidSize;
} }
MemoryPermission expectedPermission = process.Pid == _ownerPid KMemoryPermission expectedPermission = process.Pid == _ownerPid
? _ownerPermission ? _ownerPermission
: _userPermission; : _userPermission;

View file

@ -8,12 +8,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
private KProcess _creator; private KProcess _creator;
// TODO: Remove when we no longer need to read it from the owner directly.
public KProcess Creator => _creator;
private readonly KPageList _pageList; private readonly KPageList _pageList;
public ulong Address { get; private set; } public ulong Address { get; private set; }
public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize; public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize;
public MemoryPermission Permission { get; private set; } public KMemoryPermission Permission { get; private set; }
private bool _hasBeenInitialized; private bool _hasBeenInitialized;
private bool _isMapped; private bool _isMapped;
@ -23,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_pageList = new KPageList(); _pageList = new KPageList();
} }
public KernelResult Initialize(ulong address, ulong size, MemoryPermission permission) public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
{ {
KProcess creator = KernelContext.Scheduler.GetCurrentProcess(); KProcess creator = KernelContext.Scheduler.GetCurrentProcess();

View file

@ -3,7 +3,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Memory namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
[Flags] [Flags]
enum MemoryPermission : byte enum KMemoryPermission : byte
{ {
None = 0, None = 0,
Mask = 0xff, Mask = 0xff,

View file

@ -1,7 +1,7 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Diagnostics.Demangler; using Ryujinx.HLE.HOS.Diagnostics.Demangler;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.Loaders.Elf; using Ryujinx.HLE.Loaders.Elf;
using Ryujinx.Memory;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
break; break;
} }
if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute) if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute)
{ {
LoadMod0Symbols(_owner.CpuMemory, info.Address); LoadMod0Symbols(_owner.CpuMemory, info.Address);
} }
@ -235,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
} }
} }
private void LoadMod0Symbols(MemoryManager memory, ulong textOffset) private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset)
{ {
ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4); ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4);
@ -319,7 +319,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
} }
} }
private ElfSymbol GetSymbol64(MemoryManager memory, ulong address, ulong strTblAddr) private ElfSymbol GetSymbol64(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
{ {
ElfSymbol64 sym = memory.Read<ElfSymbol64>(address); ElfSymbol64 sym = memory.Read<ElfSymbol64>(address);
@ -335,7 +335,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size); return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
} }
private ElfSymbol GetSymbol32(MemoryManager memory, ulong address, ulong strTblAddr) private ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
{ {
ElfSymbol32 sym = memory.Read<ElfSymbol32>(address); ElfSymbol32 sym = memory.Read<ElfSymbol32>(address);

View 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);
}
}

View 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);
}
}

View file

@ -6,6 +6,7 @@ using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KProcess : KSynchronizationObject class KProcess : KSynchronizationObject
{ {
public const int KernelVersionMajor = 10; public const int KernelVersionMajor = 10;
public const int KernelVersionMinor = 4; public const int KernelVersionMinor = 4;
public const int KernelVersionRevision = 0; public const int KernelVersionRevision = 0;
public const int KernelVersionPacked = public const int KernelVersionPacked =
(KernelVersionMajor << 19) | (KernelVersionMajor << 19) |
(KernelVersionMinor << 15) | (KernelVersionMinor << 15) |
(KernelVersionRevision << 0); (KernelVersionRevision << 0);
public KMemoryManager MemoryManager { get; private set; } public KMemoryManager MemoryManager { get; private set; }
@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public long[] RandomEntropy { get; private set; } public long[] RandomEntropy { get; private set; }
private bool _signaled; private bool _signaled;
private bool _useSystemMemBlocks;
public string Name { get; private set; } public string Name { get; private set; }
private int _threadCount; private int _threadCount;
public int MmuFlags { get; private set; } public ProcessCreationFlags Flags { get; private set; }
private MemoryRegion _memRegion; private MemoryRegion _memRegion;
public KProcessCapabilities Capabilities { get; private set; } public KProcessCapabilities Capabilities { get; private set; }
public ulong TitleId { get; private set; } public ulong TitleId { get; private set; }
public long Pid { get; private set; } public long Pid { get; private set; }
private long _creationTimestamp; private long _creationTimestamp;
private ulong _entrypoint; private ulong _entrypoint;
private ThreadStart _customThreadStart;
private ulong _imageSize; private ulong _imageSize;
private ulong _mainThreadStackSize; private ulong _mainThreadStackSize;
private ulong _memoryUsageCapacity; private ulong _memoryUsageCapacity;
private int _version; private int _version;
public KHandleTable HandleTable { get; private set; } public KHandleTable HandleTable { get; private set; }
@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public bool IsPaused { get; private set; } public bool IsPaused { get; private set; }
public MemoryManager CpuMemory { get; private set; } private IProcessContextFactory _contextFactory;
public CpuContext CpuContext { get; private set; } public IProcessContext Context { get; private set; }
public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
public HleProcessDebugger Debugger { get; private set; } public HleProcessDebugger Debugger { get; private set; }
public KProcess(KernelContext context) : base(context) public KProcess(KernelContext context) : base(context)
{ {
_processLock = new object(); _processLock = new object();
_threadingLock = new object(); _threadingLock = new object();
AddressArbiter = new KAddressArbiter(context); AddressArbiter = new KAddressArbiter(context);
@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
RandomEntropy = new long[KScheduler.CpuCoresCount]; RandomEntropy = new long[KScheduler.CpuCoresCount];
// TODO: Remove once we no longer need to initialize it externally.
HandleTable = new KHandleTable(context);
_threads = new LinkedList<KThread>(); _threads = new LinkedList<KThread>();
Debugger = new HleProcessDebugger(this); Debugger = new HleProcessDebugger(this);
@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KernelResult InitializeKip( public KernelResult InitializeKip(
ProcessCreationInfo creationInfo, ProcessCreationInfo creationInfo,
int[] caps, ReadOnlySpan<int> capabilities,
KPageList pageList, KPageList pageList,
KResourceLimit resourceLimit, KResourceLimit resourceLimit,
MemoryRegion memRegion) MemoryRegion memRegion,
IProcessContextFactory contextFactory)
{ {
ResourceLimit = resourceLimit; ResourceLimit = resourceLimit;
_memRegion = memRegion; _memRegion = memRegion;
_contextFactory = contextFactory ?? new ProcessContextFactory();
AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
InitializeMemoryManager(addrSpaceType, memRegion); InitializeMemoryManager(creationInfo.Flags);
bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress; ulong codeAddress = creationInfo.CodeAddress;
ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0 KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
? KernelContext.LargeMemoryBlockAllocator ? KernelContext.LargeMemoryBlockAllocator
: KernelContext.SmallMemoryBlockAllocator; : KernelContext.SmallMemoryBlockAllocator;
@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result; return result;
} }
if (!ValidateCodeAddressAndSize(codeAddress, codeSize)) if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
{ {
return KernelResult.InvalidMemRange; return KernelResult.InvalidMemRange;
} }
@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
codeAddress, codeAddress,
pageList, pageList,
MemoryState.CodeStatic, MemoryState.CodeStatic,
MemoryPermission.None); KMemoryPermission.None);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
return result; return result;
} }
result = Capabilities.InitializeForKernel(caps, MemoryManager); result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KernelResult Initialize( public KernelResult Initialize(
ProcessCreationInfo creationInfo, ProcessCreationInfo creationInfo,
int[] caps, ReadOnlySpan<int> capabilities,
KResourceLimit resourceLimit, KResourceLimit resourceLimit,
MemoryRegion memRegion) MemoryRegion memRegion,
IProcessContextFactory contextFactory,
ThreadStart customThreadStart = null)
{ {
ResourceLimit = resourceLimit; ResourceLimit = resourceLimit;
_memRegion = memRegion; _memRegion = memRegion;
_contextFactory = contextFactory ?? new ProcessContextFactory();
ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.PersonalMmHeapPagesCount, memRegion); ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion);
ulong codePagesCount = (ulong)creationInfo.CodePagesCount; ulong codePagesCount = (ulong)creationInfo.CodePagesCount;
@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
} }
} }
PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount; PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount;
KMemoryBlockAllocator memoryBlockAllocator; KMemoryBlockAllocator memoryBlockAllocator;
@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
} }
else else
{ {
memoryBlockAllocator = (MmuFlags & 0x40) != 0 memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
? KernelContext.LargeMemoryBlockAllocator ? KernelContext.LargeMemoryBlockAllocator
: KernelContext.SmallMemoryBlockAllocator; : KernelContext.SmallMemoryBlockAllocator;
} }
AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
InitializeMemoryManager(addrSpaceType, memRegion); InitializeMemoryManager(creationInfo.Flags);
bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress; ulong codeAddress = creationInfo.CodeAddress;
@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result; return result;
} }
if (!ValidateCodeAddressAndSize(codeAddress, codeSize)) if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
{ {
CleanUpForError(); CleanUpForError();
@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
codeAddress, codeAddress,
codePagesCount, codePagesCount,
MemoryState.CodeStatic, MemoryState.CodeStatic,
MemoryPermission.None); KMemoryPermission.None);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result; return result;
} }
result = Capabilities.InitializeForUser(caps, MemoryManager); result = Capabilities.InitializeForUser(capabilities, MemoryManager);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
CleanUpForError(); CleanUpForError();
} }
_customThreadStart = customThreadStart;
return result; return result;
} }
private bool ValidateCodeAddressAndSize(ulong address, ulong size)
{
ulong codeRegionStart;
ulong codeRegionSize;
switch (MemoryManager.AddrSpaceWidth)
{
case 32:
codeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000;
break;
case 36:
codeRegionStart = 0x8000000;
codeRegionSize = 0x78000000;
break;
case 39:
codeRegionStart = 0x8000000;
codeRegionSize = 0x7ff8000000;
break;
default: throw new InvalidOperationException("Invalid address space width on memory manager.");
}
ulong endAddr = address + size;
ulong codeRegionEnd = codeRegionStart + codeRegionSize;
if (endAddr <= address ||
endAddr - 1 > codeRegionEnd - 1)
{
return false;
}
if (MemoryManager.InsideHeapRegion (address, size) ||
MemoryManager.InsideAliasRegion(address, size))
{
return false;
}
return true;
}
private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo) private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
{ {
// Ensure that the current kernel version is equal or above to the minimum required. // Ensure that the current kernel version is equal or above to the minimum required.
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19; uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf; uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
if (KernelContext.EnableVersionChecks) if (KernelContext.EnableVersionChecks)
@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds; _creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
MmuFlags = creationInfo.MmuFlags; Flags = creationInfo.Flags;
_version = creationInfo.Version; _version = creationInfo.Version;
TitleId = creationInfo.TitleId; TitleId = creationInfo.TitleId;
_entrypoint = creationInfo.CodeAddress; _entrypoint = creationInfo.CodeAddress;
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize; _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
_useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0; switch (Flags & ProcessCreationFlags.AddressSpaceMask)
switch ((AddressSpaceType)((MmuFlags >> 1) & 7))
{ {
case AddressSpaceType.Addr32Bits: case ProcessCreationFlags.AddressSpace32Bit:
case AddressSpaceType.Addr36Bits: case ProcessCreationFlags.AddressSpace64BitDeprecated:
case AddressSpaceType.Addr39Bits: case ProcessCreationFlags.AddressSpace64Bit:
_memoryUsageCapacity = MemoryManager.HeapRegionEnd - _memoryUsageCapacity = MemoryManager.HeapRegionEnd -
MemoryManager.HeapRegionStart; MemoryManager.HeapRegionStart;
break; break;
case AddressSpaceType.Addr32BitsNoMap: case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
_memoryUsageCapacity = MemoryManager.HeapRegionEnd - _memoryUsageCapacity = MemoryManager.HeapRegionEnd -
MemoryManager.HeapRegionStart + MemoryManager.HeapRegionStart +
MemoryManager.AliasRegionEnd - MemoryManager.AliasRegionEnd -
MemoryManager.AliasRegionStart; MemoryManager.AliasRegionStart;
break; break;
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}."); default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
} }
GenerateRandomEntropy(); GenerateRandomEntropy();
@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
} }
ulong regionStart = MemoryManager.TlsIoRegionStart; ulong regionStart = MemoryManager.TlsIoRegionStart;
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart; ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
ulong regionPagesCount = regionSize / KMemoryManager.PageSize; ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
regionStart, regionStart,
regionPagesCount, regionPagesCount,
MemoryState.ThreadLocal, MemoryState.ThreadLocal,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
out ulong tlsPageVa); out ulong tlsPageVa);
if (result != KernelResult.Success) if (result != KernelResult.Success)
@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KernelResult result = KernelResult.Success; KernelResult result = KernelResult.Success;
KTlsPageInfo pageInfo = null; KTlsPageInfo pageInfo;
if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo)) if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
{ {
@ -594,8 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
// Check if the needed size for the code and the stack will fit on the // Check if the needed size for the code and the stack will fit on the
// memory usage capacity of this Process. Also check for possible overflow // memory usage capacity of this Process. Also check for possible overflow
// on the above addition. // on the above addition.
if (neededSize > _memoryUsageCapacity || if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
neededSize < stackSizeRounded)
{ {
threadResourceLimit?.Release(LimitableResource.Thread, 1); threadResourceLimit?.Release(LimitableResource.Thread, 1);
@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize; ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;
ulong regionStart = MemoryManager.StackRegionStart; ulong regionStart = MemoryManager.StackRegionStart;
ulong regionSize = MemoryManager.StackRegionEnd - regionStart; ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
ulong regionPagesCount = regionSize / KMemoryManager.PageSize; ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
regionStart, regionStart,
regionPagesCount, regionPagesCount,
MemoryState.Stack, MemoryState.Stack,
MemoryPermission.ReadAndWrite, KMemoryPermission.ReadAndWrite,
out ulong stackBottom); out ulong stackBottom);
if (result != KernelResult.Success) if (result != KernelResult.Success)
@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
stackTop, stackTop,
mainThreadPriority, mainThreadPriority,
DefaultCpuCore, DefaultCpuCore,
this); this,
ThreadType.User,
_customThreadStart);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
SetState(newState); SetState(newState);
// TODO: We can't call KThread.Start from a non-guest thread. result = mainThread.Start();
// We will need to make some changes to allow the creation of
// dummy threads that will be used to initialize the current
// thread on KCoreContext so that GetCurrentThread doesn't fail.
/* Result = MainThread.Start();
if (Result != KernelResult.Success) if (result != KernelResult.Success)
{ {
SetState(OldState); SetState(oldState);
CleanUpForError(); CleanUpForError();
} */ }
mainThread.Reschedule(ThreadSchedState.Running);
if (result == KernelResult.Success) if (result == KernelResult.Success)
{ {
@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
if (State != newState) if (State != newState)
{ {
State = newState; State = newState;
_signaled = true; _signaled = true;
Signal(); Signal();
@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KernelResult InitializeThread( public KernelResult InitializeThread(
KThread thread, KThread thread,
ulong entrypoint, ulong entrypoint,
ulong argsPtr, ulong argsPtr,
ulong stackTop, ulong stackTop,
int priority, int priority,
int cpuCore) int cpuCore)
{ {
lock (_processLock) lock (_processLock)
{ {
return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this); return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null);
} }
} }
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context) public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
{ {
context.Interrupt += InterruptHandler; context.Interrupt += InterruptHandler;
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall; context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
context.Undefined += UndefinedInstructionHandler; context.Undefined += UndefinedInstructionHandler;
} }
private void InterruptHandler(object sender, EventArgs e) private void InterruptHandler(object sender, EventArgs e)
@ -910,8 +871,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
if (State >= ProcessState.Started) if (State >= ProcessState.Started)
{ {
if (State == ProcessState.Started || if (State == ProcessState.Started ||
State == ProcessState.Crashed || State == ProcessState.Crashed ||
State == ProcessState.Attached || State == ProcessState.Attached ||
State == ProcessState.DebugSuspended) State == ProcessState.DebugSuspended)
{ {
@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result; return result;
} }
private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion) private void InitializeMemoryManager(ProcessCreationFlags flags)
{ {
int addrSpaceBits = addrSpaceType switch int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch
{ {
AddressSpaceType.Addr32Bits => 32, ProcessCreationFlags.AddressSpace32Bit => 32,
AddressSpaceType.Addr36Bits => 36, ProcessCreationFlags.AddressSpace64BitDeprecated => 36,
AddressSpaceType.Addr32BitsNoMap => 32, ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32,
AddressSpaceType.Addr39Bits => 39, ProcessCreationFlags.AddressSpace64Bit => 39,
_ => throw new ArgumentException(nameof(addrSpaceType)) _ => 39
}; };
CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler); Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
CpuContext = new CpuContext(CpuMemory);
// TODO: This should eventually be removed. // TODO: This should eventually be removed.
// The GPU shouldn't depend on the CPU memory manager at all. // The GPU shouldn't depend on the CPU memory manager at all.
KernelContext.Device.Gpu.SetVmm(CpuMemory); if (flags.HasFlag(ProcessCreationFlags.IsApplication))
{
KernelContext.Device.Gpu.SetVmm((MemoryManager)CpuMemory);
}
MemoryManager = new KMemoryManager(KernelContext, CpuMemory); MemoryManager = new KMemoryManager(KernelContext, CpuMemory);
} }
@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
throw new UndefinedInstructionException(e.Address, e.OpCode); throw new UndefinedInstructionException(e.Address, e.OpCode);
} }
protected override void Destroy() protected override void Destroy() => Context.Dispose();
{
CpuMemory.Dispose();
}
} }
} }

View file

@ -2,6 +2,7 @@ using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
namespace Ryujinx.HLE.HOS.Kernel.Process namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
@ -24,29 +25,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
IrqAccessMask = new byte[0x80]; IrqAccessMask = new byte[0x80];
} }
public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager) public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
{ {
AllowedCpuCoresMask = 0xf; AllowedCpuCoresMask = 0xf;
AllowedThreadPriosMask = -1; AllowedThreadPriosMask = -1;
DebuggingFlags &= ~3; DebuggingFlags &= ~3;
KernelReleaseVersion = KProcess.KernelVersionPacked; KernelReleaseVersion = KProcess.KernelVersionPacked;
return Parse(caps, memoryManager); return Parse(capabilities, memoryManager);
} }
public KernelResult InitializeForUser(int[] caps, KMemoryManager memoryManager) public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
{ {
return Parse(caps, memoryManager); return Parse(capabilities, memoryManager);
} }
private KernelResult Parse(int[] caps, KMemoryManager memoryManager) private KernelResult Parse(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
{ {
int mask0 = 0; int mask0 = 0;
int mask1 = 0; int mask1 = 0;
for (int index = 0; index < caps.Length; index++) for (int index = 0; index < capabilities.Length; index++)
{ {
int cap = caps[index]; int cap = capabilities[index];
if (((cap + 1) & ~cap) != 0x40) if (((cap + 1) & ~cap) != 0x40)
{ {
@ -59,14 +60,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
} }
else else
{ {
if ((uint)index + 1 >= caps.Length) if ((uint)index + 1 >= capabilities.Length)
{ {
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
int prevCap = cap; int prevCap = cap;
cap = caps[++index]; cap = capabilities[++index];
if (((cap + 1) & ~cap) != 0x40) if (((cap + 1) & ~cap) != 0x40)
{ {
@ -91,9 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return KernelResult.InvalidAddress; return KernelResult.InvalidAddress;
} }
MemoryPermission perm = (prevCap >> 31) != 0 KMemoryPermission perm = (prevCap >> 31) != 0
? MemoryPermission.Read ? KMemoryPermission.Read
: MemoryPermission.ReadAndWrite; : KMemoryPermission.ReadAndWrite;
KernelResult result; KernelResult result;
@ -216,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
long address = ((long)(uint)cap << 4) & 0xffffff000; long address = ((long)(uint)cap << 4) & 0xffffff000;
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite); memoryManager.MapIoMemory(address, KMemoryManager.PageSize, KMemoryPermission.ReadAndWrite);
break; break;
} }

View 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()
{
}
}
}

View 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));
}
}
}

View 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
}
}

View file

@ -2,36 +2,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
struct ProcessCreationInfo struct ProcessCreationInfo
{ {
public string Name { get; private set; } public string Name { get; }
public int Version { get; private set; } public int Version { get; }
public ulong TitleId { get; private set; } public ulong TitleId { get; }
public ulong CodeAddress { get; private set; } public ulong CodeAddress { get; }
public int CodePagesCount { get; private set; } public int CodePagesCount { get; }
public int MmuFlags { get; private set; } public ProcessCreationFlags Flags { get; }
public int ResourceLimitHandle { get; private set; } public int ResourceLimitHandle { get; }
public int PersonalMmHeapPagesCount { get; private set; } public int SystemResourcePagesCount { get; }
public ProcessCreationInfo( public ProcessCreationInfo(
string name, string name,
int category, int version,
ulong titleId, ulong titleId,
ulong codeAddress, ulong codeAddress,
int codePagesCount, int codePagesCount,
int mmuFlags, ProcessCreationFlags flags,
int resourceLimitHandle, int resourceLimitHandle,
int personalMmHeapPagesCount) int systemResourcePagesCount)
{ {
Name = name; Name = name;
Version = category; Version = version;
TitleId = titleId; TitleId = titleId;
CodeAddress = codeAddress; CodeAddress = codeAddress;
CodePagesCount = codePagesCount; CodePagesCount = codePagesCount;
MmuFlags = mmuFlags; Flags = flags;
ResourceLimitHandle = resourceLimitHandle; ResourceLimitHandle = resourceLimitHandle;
PersonalMmHeapPagesCount = personalMmHeapPagesCount; SystemResourcePagesCount = systemResourcePagesCount;
} }
} }
} }

View file

@ -7,21 +7,167 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Memory;
using System; using System;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{ {
class Syscall class Syscall
{ {
private readonly Switch _device;
private readonly KernelContext _context; private readonly KernelContext _context;
public Syscall(Switch device, KernelContext context) public Syscall(KernelContext context)
{ {
_device = device;
_context = context; _context = context;
} }
// Process
public KernelResult GetProcessId(int handle, out long pid)
{
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process == null)
{
KThread thread = currentProcess.HandleTable.GetKThread(handle);
if (thread != null)
{
process = thread.Owner;
}
// TODO: KDebugEvent.
}
pid = process?.Pid ?? 0;
return process != null
? KernelResult.Success
: KernelResult.InvalidHandle;
}
public KernelResult CreateProcess(
ProcessCreationInfo info,
ReadOnlySpan<int> capabilities,
out int handle,
IProcessContextFactory contextFactory,
ThreadStart customThreadStart = null)
{
handle = 0;
if ((info.Flags & ~ProcessCreationFlags.All) != 0)
{
return KernelResult.InvalidEnumValue;
}
// TODO: Address space check.
if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
{
return KernelResult.InvalidEnumValue;
}
if ((info.CodeAddress & 0x1fffff) != 0)
{
return KernelResult.InvalidAddress;
}
if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
{
return KernelResult.InvalidSize;
}
if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
!info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
{
return KernelResult.InvalidThread;
}
KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable;
KProcess process = new KProcess(_context);
using var _ = new OnScopeExit(process.DecrementReferenceCount);
KResourceLimit resourceLimit;
if (info.ResourceLimitHandle != 0)
{
resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
if (resourceLimit == null)
{
return KernelResult.InvalidHandle;
}
}
else
{
resourceLimit = _context.ResourceLimit;
}
MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch
{
ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application,
ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet,
ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service,
ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices,
_ => MemoryRegion.NvServices
};
KernelResult result = process.Initialize(
info,
capabilities,
resourceLimit,
memRegion,
contextFactory,
customThreadStart);
if (result != KernelResult.Success)
{
return result;
}
_context.Processes.TryAdd(process.Pid, process);
return handleTable.GenerateHandle(process, out handle);
}
public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
{
KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
if (process == null)
{
return KernelResult.InvalidHandle;
}
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
{
return KernelResult.InvalidCpuCore;
}
if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority))
{
return KernelResult.InvalidPriority;
}
process.DefaultCpuCore = cpuCore;
KernelResult result = process.Start(priority, mainThreadStackSize);
if (result != KernelResult.Success)
{
return result;
}
process.IncrementReferenceCount();
return KernelResult.Success;
}
// IPC // IPC
public KernelResult ConnectToNamedPort(ulong namePtr, out int handle) public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
@ -33,6 +179,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }
return ConnectToNamedPort(name, out handle);
}
public KernelResult ConnectToNamedPort(string name, out int handle)
{
handle = 0;
if (name.Length > 11) if (name.Length > 11)
{ {
return KernelResult.MaximumExceeded; return KernelResult.MaximumExceeded;
@ -70,61 +223,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result; return result;
} }
public KernelResult SendSyncRequestHLE(int handle) public KernelResult SendSyncRequest(int handle)
{
KProcess process = _context.Scheduler.GetCurrentProcess();
KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
if (clientSession == null || clientSession.Service == null)
{
return SendSyncRequest(handle);
}
return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
}
public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle)
{
KProcess process = _context.Scheduler.GetCurrentProcess();
byte[] messageData = new byte[messageSize];
process.CpuMemory.Read(messagePtr, messageData);
KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
if (clientSession == null || clientSession.Service == null)
{
return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
}
if (clientSession != null)
{
_context.CriticalSection.Enter();
KThread currentThread = _context.Scheduler.GetCurrentThread();
currentThread.SignaledObj = null;
currentThread.ObjSyncResult = KernelResult.Success;
currentThread.Reschedule(ThreadSchedState.Paused);
clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize);
_context.CriticalSection.Leave();
return currentThread.ObjSyncResult;
}
else
{
Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
return KernelResult.InvalidHandle;
}
}
private KernelResult SendSyncRequest(int handle)
{ {
KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount]; return ReplyAndReceive(handles, replyTargetHandle, timeout, out handleIndex);
}
for (int index = 0; index < handlesCount; index++) public KernelResult ReplyAndReceive(ReadOnlySpan<int> handles, int replyTargetHandle, long timeout, out int handleIndex)
{
handleIndex = 0;
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handles.Length];
for (int index = 0; index < handles.Length; index++)
{ {
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]); KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }
if (maxSessions < 0 || name.Length > 11) if (name.Length > 11)
{
return KernelResult.MaximumExceeded;
}
return ManageNamedPort(name, maxSessions, out handle);
}
public KernelResult ManageNamedPort(string name, int maxSessions, out int handle)
{
handle = 0;
if (maxSessions < 0)
{ {
return KernelResult.MaximumExceeded; return KernelResult.MaximumExceeded;
} }
@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success; return KernelResult.Success;
} }
public KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission) public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
{ {
if (!PageAligned(address)) if (!PageAligned(address))
{ {
@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
{ {
return KernelResult.InvalidPermission; return KernelResult.InvalidPermission;
} }
@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess); currentProcess);
} }
public KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle) public KernelResult CreateTransferMemory(ulong address, ulong size, KMemoryPermission permission, out int handle)
{ {
handle = 0; handle = 0;
@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidMemState; return KernelResult.InvalidMemState;
} }
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write) if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
{ {
return KernelResult.InvalidPermission; return KernelResult.InvalidPermission;
} }
@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size); return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
} }
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission) public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission)
{ {
if (!PageAligned(src)) if (!PageAligned(src))
{ {
@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidSize; return KernelResult.InvalidSize;
} }
if (permission != MemoryPermission.None && if (permission != KMemoryPermission.None &&
permission != MemoryPermission.Read && permission != KMemoryPermission.Read &&
permission != MemoryPermission.ReadAndWrite && permission != KMemoryPermission.ReadAndWrite &&
permission != MemoryPermission.ReadAndExecute) permission != KMemoryPermission.ReadAndExecute)
{ {
return KernelResult.InvalidPermission; return KernelResult.InvalidPermission;
} }
@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _context.Scheduler.GetCurrentThread().Context.CntpctEl0; return _context.Scheduler.GetCurrentThread().Context.CntpctEl0;
} }
public KernelResult GetProcessId(int handle, out long pid)
{
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process == null)
{
KThread thread = currentProcess.HandleTable.GetKThread(handle);
if (thread != null)
{
process = thread.Owner;
}
// TODO: KDebugEvent.
}
pid = process?.Pid ?? 0;
return process != null
? KernelResult.Success
: KernelResult.InvalidHandle;
}
public void Break(ulong reason) public void Break(ulong reason)
{ {
KThread currentThread = _context.Scheduler.GetCurrentThread(); KThread currentThread = _context.Scheduler.GetCurrentThread();
@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidThread; return KernelResult.InvalidThread;
} }
MemoryManager memory = currentProcess.CpuMemory; IVirtualMemoryManager memory = currentProcess.CpuMemory;
memory.Write(address + 0x0, thread.Context.GetX(0)); memory.Write(address + 0x0, thread.Context.GetX(0));
memory.Write(address + 0x8, thread.Context.GetX(1)); memory.Write(address + 0x8, thread.Context.GetX(1));

View file

@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult SendSyncRequest32([R(0)] int handle) public KernelResult SendSyncRequest32([R(0)] int handle)
{ {
return _syscall.SendSyncRequestHLE(handle); return _syscall.SendSyncRequest(handle);
} }
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle) public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle)
{ {
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle); return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
} }
public KernelResult CreateSession32( public KernelResult CreateSession32(
@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result; return result;
} }
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission) public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission)
{ {
return _syscall.MapSharedMemory(handle, address, size, permission); return _syscall.MapSharedMemory(handle, address, size, permission);
} }
@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult CreateTransferMemory32( public KernelResult CreateTransferMemory32(
[R(1)] uint address, [R(1)] uint address,
[R(2)] uint size, [R(2)] uint size,
[R(3)] MemoryPermission permission, [R(3)] KMemoryPermission permission,
[R(1)] out int handle) [R(1)] out int handle)
{ {
return _syscall.CreateTransferMemory(address, size, permission, out handle); return _syscall.CreateTransferMemory(address, size, permission, out handle);
@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
[R(2)] uint srcLow, [R(2)] uint srcLow,
[R(3)] uint srcHigh, [R(3)] uint srcHigh,
[R(4)] uint sizeHigh, [R(4)] uint sizeHigh,
[R(5)] MemoryPermission permission) [R(5)] KMemoryPermission permission)
{ {
ulong src = srcLow | ((ulong)srcHigh << 32); ulong src = srcLow | ((ulong)srcHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32); ulong size = sizeLow | ((ulong)sizeHigh << 32);

View file

@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult SendSyncRequest64([R(0)] int handle) public KernelResult SendSyncRequest64([R(0)] int handle)
{ {
return _syscall.SendSyncRequestHLE(handle); return _syscall.SendSyncRequest(handle);
} }
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle) public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle)
{ {
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle); return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
} }
public KernelResult SendAsyncRequestWithUserBuffer64( public KernelResult SendAsyncRequestWithUserBuffer64(
@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _syscall.QueryMemory(infoPtr, position, out pageInfo); return _syscall.QueryMemory(infoPtr, position, out pageInfo);
} }
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission) public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{ {
return _syscall.MapSharedMemory(handle, address, size, permission); return _syscall.MapSharedMemory(handle, address, size, permission);
} }
@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public KernelResult CreateTransferMemory64( public KernelResult CreateTransferMemory64(
[R(1)] ulong address, [R(1)] ulong address,
[R(2)] ulong size, [R(2)] ulong size,
[R(3)] MemoryPermission permission, [R(3)] KMemoryPermission permission,
[R(1)] out int handle) [R(1)] out int handle)
{ {
return _syscall.CreateTransferMemory(address, size, permission, out handle); return _syscall.CreateTransferMemory(address, size, permission, out handle);
@ -172,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size); return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
} }
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission) public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{ {
return _syscall.SetProcessMemoryPermission(handle, src, size, permission); return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
} }

View file

@ -229,6 +229,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KProcess dummyProcess = new KProcess(_context); KProcess dummyProcess = new KProcess(_context);
dummyProcess.HandleTable.Initialize(1024);
KThread dummyThread = new KThread(_context); KThread dummyThread = new KThread(_context);
dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy); dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy);

View file

@ -31,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public ulong CondVarAddress { get; set; } public ulong CondVarAddress { get; set; }
private ulong _entrypoint; private ulong _entrypoint;
private ThreadStart _customThreadStart;
public ulong MutexAddress { get; set; } public ulong MutexAddress { get; set; }
@ -48,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; } public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
public LinkedList<KThread> Withholder { get; set; } public LinkedList<KThread> Withholder { get; set; }
public LinkedListNode<KThread> WithholderNode { get; set; } public LinkedListNode<KThread> WithholderNode { get; set; }
public LinkedListNode<KThread> ProcessListNode { get; set; } public LinkedListNode<KThread> ProcessListNode { get; set; }
private LinkedList<KThread> _mutexWaiters; private LinkedList<KThread> _mutexWaiters;
private LinkedListNode<KThread> _mutexWaiterNode; private LinkedListNode<KThread> _mutexWaiterNode;
public KThread MutexOwner { get; private set; } public KThread MutexOwner { get; private set; }
@ -65,24 +66,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public KernelResult ObjSyncResult { get; set; } public KernelResult ObjSyncResult { get; set; }
public int DynamicPriority { get; set; } public int DynamicPriority { get; set; }
public int CurrentCore { get; set; } public int CurrentCore { get; set; }
public int BasePriority { get; set; } public int BasePriority { get; set; }
public int PreferredCore { get; set; } public int PreferredCore { get; set; }
private long _affinityMaskOverride; private long _affinityMaskOverride;
private int _preferredCoreOverride; private int _preferredCoreOverride;
#pragma warning disable CS0649 #pragma warning disable CS0649
private int _affinityOverrideCount; private int _affinityOverrideCount;
#pragma warning restore CS0649 #pragma warning restore CS0649
public ThreadSchedState SchedFlags { get; private set; } public ThreadSchedState SchedFlags { get; private set; }
private int _shallBeTerminated; private int _shallBeTerminated;
public bool ShallBeTerminated { get => _shallBeTerminated != 0; set => _shallBeTerminated = value ? 1 : 0; } public bool ShallBeTerminated
{
get => _shallBeTerminated != 0;
set => _shallBeTerminated = value ? 1 : 0;
}
public bool SyncCancelled { get; set; } public bool SyncCancelled { get; set; }
public bool WaitingSync { get; set; } public bool WaitingSync { get; set; }
private bool _hasExited; private bool _hasExited;
private bool _hasBeenInitialized; private bool _hasBeenInitialized;
@ -98,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public KThread(KernelContext context) : base(context) public KThread(KernelContext context) : base(context)
{ {
_scheduler = KernelContext.Scheduler; _scheduler = KernelContext.Scheduler;
_schedulingData = KernelContext.Scheduler.SchedulingData; _schedulingData = KernelContext.Scheduler.SchedulingData;
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects]; WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
@ -110,14 +115,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
public KernelResult Initialize( public KernelResult Initialize(
ulong entrypoint, ulong entrypoint,
ulong argsPtr, ulong argsPtr,
ulong stackTop, ulong stackTop,
int priority, int priority,
int defaultCpuCore, int defaultCpuCore,
KProcess owner, KProcess owner,
ThreadType type = ThreadType.User, ThreadType type,
ThreadStart customHostThreadStart = null) ThreadStart customThreadStart = null)
{ {
if ((uint)type > 3) if ((uint)type > 3)
{ {
@ -135,11 +140,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
CurrentCore = PreferredCore; CurrentCore = PreferredCore;
DynamicPriority = priority; DynamicPriority = priority;
BasePriority = priority; BasePriority = priority;
ObjSyncResult = KernelResult.ThreadNotStarted; ObjSyncResult = KernelResult.ThreadNotStarted;
_entrypoint = entrypoint; _entrypoint = entrypoint;
_customThreadStart = customThreadStart;
if (type == ThreadType.User) if (type == ThreadType.User)
{ {
@ -162,18 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
owner.IncrementReferenceCount(); owner.IncrementReferenceCount();
owner.IncrementThreadCount(); owner.IncrementThreadCount();
is64Bits = (owner.MmuFlags & 1) != 0; is64Bits = owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
} }
else else
{ {
is64Bits = true; is64Bits = true;
} }
HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint))); HostThread = new Thread(ThreadStart);
Context = CpuContext.CreateExecutionContext(); Context = CpuContext.CreateExecutionContext();
bool isAarch32 = (Owner.MmuFlags & 1) == 0; bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
Context.IsAarch32 = isAarch32; Context.IsAarch32 = isAarch32;
@ -189,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
Context.CntfrqEl0 = 19200000; Context.CntfrqEl0 = 19200000;
Context.Tpidr = (long)_tlsAddress; Context.Tpidr = (long)_tlsAddress;
owner.SubscribeThreadEventHandlers(Context); owner.SubscribeThreadEventHandlers(Context);
@ -249,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
KThread currentThread = KernelContext.Scheduler.GetCurrentThread(); KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
while (SchedFlags != ThreadSchedState.TerminationPending && while (SchedFlags != ThreadSchedState.TerminationPending &&
currentThread.SchedFlags != ThreadSchedState.TerminationPending && currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
!currentThread.ShallBeTerminated) !currentThread.ShallBeTerminated)
{ {
@ -351,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Context.RequestInterrupt(); Context.RequestInterrupt();
} }
SignaledObj = null; SignaledObj = null;
ObjSyncResult = KernelResult.ThreadTerminating; ObjSyncResult = KernelResult.ThreadTerminating;
ReleaseAndResume(); ReleaseAndResume();
@ -524,7 +530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
// If the candidate was scheduled after the current thread, then it's not worth it, // If the candidate was scheduled after the current thread, then it's not worth it,
// unless the priority is higher than the current one. // unless the priority is higher than the current one.
if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime || if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority) nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
{ {
yield return thread; yield return thread;
} }
@ -701,7 +707,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
else else
{ {
SignaledObj = null; SignaledObj = null;
ObjSyncResult = KernelResult.Cancelled; ObjSyncResult = KernelResult.Cancelled;
SetNewSchedFlags(ThreadSchedState.Running); SetNewSchedFlags(ThreadSchedState.Running);
@ -734,14 +740,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (useOverride) if (useOverride)
{ {
_preferredCoreOverride = newCore; _preferredCoreOverride = newCore;
_affinityMaskOverride = newAffinityMask; _affinityMaskOverride = newAffinityMask;
} }
else else
{ {
long oldAffinityMask = AffinityMask; long oldAffinityMask = AffinityMask;
PreferredCore = newCore; PreferredCore = newCore;
AffinityMask = newAffinityMask; AffinityMask = newAffinityMask;
if (oldAffinityMask != newAffinityMask) if (oldAffinityMask != newAffinityMask)
{ {
@ -783,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private void CombineForcePauseFlags() private void CombineForcePauseFlags()
{ {
ThreadSchedState oldFlags = SchedFlags; ThreadSchedState oldFlags = SchedFlags;
ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask; ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
SchedFlags = lowNibble | _forcePauseFlags; SchedFlags = lowNibble | _forcePauseFlags;
@ -1143,19 +1149,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
} }
private void ThreadStart(ulong entrypoint) private void ThreadStart()
{ {
Owner.CpuContext.Execute(Context, entrypoint); KernelStatic.SetKernelContext(KernelContext);
ThreadExit(); if (_customThreadStart != null)
{
_customThreadStart();
}
else
{
Owner.Context.Execute(Context, _entrypoint);
}
Context.Dispose();
}
private void ThreadExit()
{
KernelContext.Scheduler.ExitThread(this); KernelContext.Scheduler.ExitThread(this);
KernelContext.Scheduler.RemoveThread(this); KernelContext.Scheduler.RemoveThread(this);
Context.Dispose();
} }
public bool IsCurrentHostThread() public bool IsCurrentHostThread()
@ -1203,9 +1213,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
// Wake up all threads that may be waiting for a mutex being held by this thread. // Wake up all threads that may be waiting for a mutex being held by this thread.
foreach (KThread thread in _mutexWaiters) foreach (KThread thread in _mutexWaiters)
{ {
thread.MutexOwner = null; thread.MutexOwner = null;
thread._preferredCoreOverride = 0; thread._preferredCoreOverride = 0;
thread.ObjSyncResult = KernelResult.InvalidState; thread.ObjSyncResult = KernelResult.InvalidState;
thread.ReleaseAndResume(); thread.ReleaseAndResume();
} }

View file

@ -36,23 +36,23 @@ namespace Ryujinx.HLE.HOS
ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset; ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;
int mmuFlags = 0; ProcessCreationFlags flags = 0;
if (AslrEnabled) if (AslrEnabled)
{ {
// TODO: Randomization. // TODO: Randomization.
mmuFlags |= 0x20; flags |= ProcessCreationFlags.EnableAslr;
} }
if (kip.Is64BitAddressSpace) if (kip.Is64BitAddressSpace)
{ {
mmuFlags |= (int)AddressSpaceType.Addr39Bits << 1; flags |= ProcessCreationFlags.AddressSpace64Bit;
} }
if (kip.Is64Bit) if (kip.Is64Bit)
{ {
mmuFlags |= 1; flags |= ProcessCreationFlags.Is64Bit;
} }
ProcessCreationInfo creationInfo = new ProcessCreationInfo( ProcessCreationInfo creationInfo = new ProcessCreationInfo(
@ -61,7 +61,7 @@ namespace Ryujinx.HLE.HOS
kip.ProgramId, kip.ProgramId,
codeAddress, codeAddress,
codePagesCount, codePagesCount,
mmuFlags, flags,
0, 0,
0); 0);
@ -82,12 +82,15 @@ namespace Ryujinx.HLE.HOS
KProcess process = new KProcess(context); KProcess process = new KProcess(context);
var processContextFactory = new ArmProcessContextFactory();
result = process.InitializeKip( result = process.InitializeKip(
creationInfo, creationInfo,
kip.Capabilities, kip.Capabilities,
pageList, pageList,
context.ResourceLimit, context.ResourceLimit,
memoryRegion); memoryRegion,
processContextFactory);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -183,7 +186,7 @@ namespace Ryujinx.HLE.HOS
metaData.Aci0.TitleId, metaData.Aci0.TitleId,
codeStart, codeStart,
codePagesCount, codePagesCount,
metaData.MmuFlags, (ProcessCreationFlags)metaData.ProcessFlags | ProcessCreationFlags.IsApplication,
0, 0,
personalMmHeapPagesCount); personalMmHeapPagesCount);
@ -217,11 +220,14 @@ namespace Ryujinx.HLE.HOS
return false; return false;
} }
var processContextFactory = new ArmProcessContextFactory();
result = process.Initialize( result = process.Initialize(
creationInfo, creationInfo,
metaData.Aci0.KernelAccessControl.Capabilities, metaData.Aci0.KernelAccessControl.Capabilities,
resourceLimit, resourceLimit,
memoryRegion); memoryRegion,
processContextFactory);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
@ -280,7 +286,7 @@ namespace Ryujinx.HLE.HOS
MemoryHelper.FillWithZeros(process.CpuMemory, (long)bssStart, image.BssSize); MemoryHelper.FillWithZeros(process.CpuMemory, (long)bssStart, image.BssSize);
KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission) KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{ {
if (size == 0) if (size == 0)
{ {
@ -292,21 +298,21 @@ namespace Ryujinx.HLE.HOS
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission); return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
} }
KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, MemoryPermission.ReadAndExecute); KernelResult result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
return result; return result;
} }
result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, MemoryPermission.Read); result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
if (result != KernelResult.Success) if (result != KernelResult.Success)
{ {
return result; return result;
} }
return SetProcessMemoryPermission(dataStart, end - dataStart, MemoryPermission.ReadAndWrite); return SetProcessMemoryPermission(dataStart, end - dataStart, KMemoryPermission.ReadAndWrite);
} }
} }
} }

View file

@ -1,43 +1,39 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Memory;
using System.IO; using System.IO;
namespace Ryujinx.HLE.HOS namespace Ryujinx.HLE.HOS
{ {
class ServiceCtx class ServiceCtx
{ {
public Switch Device { get; } public Switch Device { get; }
public KProcess Process { get; } public KProcess Process { get; }
public MemoryManager Memory { get; } public IVirtualMemoryManager Memory { get; }
public KThread Thread { get; } public KThread Thread { get; }
public KClientSession Session { get; } public IpcMessage Request { get; }
public IpcMessage Request { get; } public IpcMessage Response { get; }
public IpcMessage Response { get; } public BinaryReader RequestData { get; }
public BinaryReader RequestData { get; } public BinaryWriter ResponseData { get; }
public BinaryWriter ResponseData { get; }
public ServiceCtx( public ServiceCtx(
Switch device, Switch device,
KProcess process, KProcess process,
MemoryManager memory, IVirtualMemoryManager memory,
KThread thread, KThread thread,
KClientSession session, IpcMessage request,
IpcMessage request, IpcMessage response,
IpcMessage response, BinaryReader requestData,
BinaryReader requestData, BinaryWriter responseData)
BinaryWriter responseData)
{ {
Device = device; Device = device;
Process = process; Process = process;
Memory = memory; Memory = memory;
Thread = thread; Thread = thread;
Session = session; Request = request;
Request = request; Response = response;
Response = response; RequestData = requestData;
RequestData = requestData;
ResponseData = responseData; ResponseData = responseData;
} }
} }

View file

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

View file

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

View file

@ -12,7 +12,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
private Apm.SystemManagerServer _apmSystemManagerServer; private Apm.SystemManagerServer _apmSystemManagerServer;
private Lbl.LblControllerServer _lblControllerServer; private Lbl.LblControllerServer _lblControllerServer;
private bool _vrModeEnabled = false; private bool _vrModeEnabled;
private int _messageEventHandle;
private int _displayResolutionChangedEventHandle;
public ICommonStateGetter(ServiceCtx context) public ICommonStateGetter(ServiceCtx context)
{ {
@ -25,14 +27,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// GetEventHandle() -> handle<copy> // GetEventHandle() -> handle<copy>
public ResultCode GetEventHandle(ServiceCtx context) public ResultCode GetEventHandle(ServiceCtx context)
{ {
KEvent Event = context.Device.System.AppletState.MessageEvent; KEvent messageEvent = context.Device.System.AppletState.MessageEvent;
if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success) if (_messageEventHandle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(messageEvent.ReadableEvent, out _messageEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_messageEventHandle);
return ResultCode.Success; return ResultCode.Success;
} }
@ -164,12 +169,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// GetDefaultDisplayResolutionChangeEvent() -> handle<copy> // GetDefaultDisplayResolutionChangeEvent() -> handle<copy>
public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context) public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
{ {
if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success) if (_displayResolutionChangedEventHandle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_displayResolutionChangedEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceAm); Logger.Stub?.PrintStub(LogClass.ServiceAm);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -28,6 +28,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
private KEvent _friendInvitationStorageChannelEvent; private KEvent _friendInvitationStorageChannelEvent;
private KEvent _notificationStorageChannelEvent; private KEvent _notificationStorageChannelEvent;
private int _gpuErrorDetectedSystemEventHandle;
private int _friendInvitationStorageChannelEventHandle;
private int _notificationStorageChannelEventHandle;
public IApplicationFunctions(Horizon system) public IApplicationFunctions(Horizon system)
{ {
_gpuErrorDetectedSystemEvent = new KEvent(system.KernelContext); _gpuErrorDetectedSystemEvent = new KEvent(system.KernelContext);
@ -293,12 +297,10 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height); resultCode = InitializeApplicationCopyrightFrameBufferImpl(transferMemoryAddress, transferMemorySize, width, height);
} }
/* if (transferMemoryHandle != 0)
if (transferMemoryHandle)
{ {
svcCloseHandle(transferMemoryHandle); context.Device.System.KernelContext.Syscall.CloseHandle(transferMemoryHandle);
} }
*/
return resultCode; return resultCode;
} }
@ -455,12 +457,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetGpuErrorDetectedSystemEvent() -> handle<copy> // GetGpuErrorDetectedSystemEvent() -> handle<copy>
public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context) public ResultCode GetGpuErrorDetectedSystemEvent(ServiceCtx context)
{ {
if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out int gpuErrorDetectedSystemEventHandle) != KernelResult.Success) if (_gpuErrorDetectedSystemEventHandle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(_gpuErrorDetectedSystemEvent.ReadableEvent, out _gpuErrorDetectedSystemEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(gpuErrorDetectedSystemEventHandle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_gpuErrorDetectedSystemEventHandle);
// NOTE: This is used by "sdk" NSO during applet-application initialization. // NOTE: This is used by "sdk" NSO during applet-application initialization.
// A seperate thread is setup where event-waiting is handled. // A seperate thread is setup where event-waiting is handled.
@ -473,12 +478,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetFriendInvitationStorageChannelEvent() -> handle<copy> // GetFriendInvitationStorageChannelEvent() -> handle<copy>
public ResultCode GetFriendInvitationStorageChannelEvent(ServiceCtx context) public ResultCode GetFriendInvitationStorageChannelEvent(ServiceCtx context)
{ {
if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out int friendInvitationStorageChannelEventHandle) != KernelResult.Success) if (_friendInvitationStorageChannelEventHandle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(_friendInvitationStorageChannelEvent.ReadableEvent, out _friendInvitationStorageChannelEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(friendInvitationStorageChannelEventHandle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_friendInvitationStorageChannelEventHandle);
return ResultCode.Success; return ResultCode.Success;
} }
@ -501,12 +509,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetNotificationStorageChannelEvent() -> handle<copy> // GetNotificationStorageChannelEvent() -> handle<copy>
public ResultCode GetNotificationStorageChannelEvent(ServiceCtx context) public ResultCode GetNotificationStorageChannelEvent(ServiceCtx context)
{ {
if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out int notificationStorageChannelEventHandle) != KernelResult.Success) if (_notificationStorageChannelEventHandle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(_notificationStorageChannelEvent.ReadableEvent, out _notificationStorageChannelEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(notificationStorageChannelEventHandle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationStorageChannelEventHandle);
return ResultCode.Success; return ResultCode.Success;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -138,12 +138,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID and owner ID if they're not already set // Workaround that by setting the application ID and owner ID if they're not already set
if (attribute.ProgramId == ProgramId.InvalidId) if (attribute.ProgramId == ProgramId.InvalidId)
{ {
attribute.ProgramId = new ProgramId(context.Process.TitleId); attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
}
if (creationInfo.OwnerId == 0)
{
creationInfo.OwnerId = 0;
} }
Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}"); Logger.Info?.Print(LogClass.ServiceFs, $"Creating save with title ID {attribute.ProgramId.Value:x16}");
@ -215,12 +210,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID and owner ID if they're not already set // Workaround that by setting the application ID and owner ID if they're not already set
if (attribute.ProgramId == ProgramId.InvalidId) if (attribute.ProgramId == ProgramId.InvalidId)
{ {
attribute.ProgramId = new ProgramId(context.Process.TitleId); attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
}
if (creationInfo.OwnerId == 0)
{
creationInfo.OwnerId = 0;
} }
Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt); Result result = _baseFileSystemProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref creationInfo, ref metaCreateInfo, ref hashSalt);
@ -239,7 +229,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID if it's not already set // Workaround that by setting the application ID if it's not already set
if (attribute.ProgramId == ProgramId.InvalidId) if (attribute.ProgramId == ProgramId.InvalidId)
{ {
attribute.ProgramId = new ProgramId(context.Process.TitleId); attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
} }
Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); Result result = _baseFileSystemProxy.OpenSaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);
@ -280,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// Workaround that by setting the application ID if it's not already set // Workaround that by setting the application ID if it's not already set
if (attribute.ProgramId == ProgramId.InvalidId) if (attribute.ProgramId == ProgramId.InvalidId)
{ {
attribute.ProgramId = new ProgramId(context.Process.TitleId); attribute.ProgramId = new ProgramId(context.Device.Application.TitleId);
} }
Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute); Result result = _baseFileSystemProxy.OpenReadOnlySaveDataFileSystem(out LibHac.Fs.Fsa.IFileSystem fileSystem, spaceId, ref attribute);

View file

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

View file

@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
private HidAccelerometerParameters _accelerometerParams; private HidAccelerometerParameters _accelerometerParams;
private HidVibrationValue _vibrationValue; private HidVibrationValue _vibrationValue;
public IHidServer(ServiceCtx context) : base(new ServerBase("HidServer")) public IHidServer(ServiceCtx context) : base(new ServerBase(context.Device.System.KernelContext, "HidServer"))
{ {
_xpadIdEvent = new KEvent(context.Device.System.KernelContext); _xpadIdEvent = new KEvent(context.Device.System.KernelContext);
_palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext); _palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);

View file

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

View file

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

View file

@ -11,6 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
private KEvent _event0; private KEvent _event0;
private KEvent _event1; private KEvent _event1;
private int _event0Handle;
private int _event1Handle;
private uint _version; private uint _version;
public IRequest(Horizon system, uint version) public IRequest(Horizon system, uint version)
@ -50,17 +53,23 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
// GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>) // GetSystemEventReadableHandles() -> (handle<copy>, handle<copy>)
public ResultCode GetSystemEventReadableHandles(ServiceCtx context) public ResultCode GetSystemEventReadableHandles(ServiceCtx context)
{ {
if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success) if (_event0Handle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out _event0Handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success) if (_event1Handle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out _event1Handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_event0Handle, _event1Handle);
return ResultCode.Success; return ResultCode.Success;
} }

View file

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

View file

@ -9,7 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Ns
[Service("aoc:u")] [Service("aoc:u")]
class IAddOnContentManager : IpcService class IAddOnContentManager : IpcService
{ {
KEvent _addOnContentListChangedEvent; private readonly KEvent _addOnContentListChangedEvent;
private int _addOnContentListChangedEventHandle;
public IAddOnContentManager(ServiceCtx context) public IAddOnContentManager(ServiceCtx context)
{ {
@ -135,12 +137,15 @@ namespace Ryujinx.HLE.HOS.Services.Ns
{ {
// Official code seems to make an internal call to ns:am Cmd 84 GetDynamicCommitEvent() // Official code seems to make an internal call to ns:am Cmd 84 GetDynamicCommitEvent()
if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out int handle) != KernelResult.Success) if (_addOnContentListChangedEventHandle == 0)
{ {
throw new InvalidOperationException("Out of handles!"); if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
} }
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_addOnContentListChangedEventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceNs); Logger.Stub?.PrintStub(LogClass.ServiceNs);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

Some files were not shown because too many files have changed in this diff Show more