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<InstExceptionEventArgs> Break;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

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,
stateMask,
stateMask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
attributeMask,
MemoryAttribute.None,
desc.ServerAddress);
@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
clientEndAddr - clientEndAddrTruncated,
stateMask,
stateMask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
attributeMask,
MemoryAttribute.None,
serverEndAddrTruncated);

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

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
{
public string Name { get; private set; }
public string Name { get; }
public int Version { get; private set; }
public ulong TitleId { get; private set; }
public int Version { get; }
public ulong TitleId { get; }
public ulong CodeAddress { get; private set; }
public int CodePagesCount { get; private set; }
public ulong CodeAddress { get; }
public int CodePagesCount { get; }
public int MmuFlags { get; private set; }
public int ResourceLimitHandle { get; private set; }
public int PersonalMmHeapPagesCount { get; private set; }
public ProcessCreationFlags Flags { get; }
public int ResourceLimitHandle { get; }
public int SystemResourcePagesCount { get; }
public ProcessCreationInfo(
string name,
int category,
ulong titleId,
ulong codeAddress,
int codePagesCount,
int mmuFlags,
int resourceLimitHandle,
int personalMmHeapPagesCount)
int version,
ulong titleId,
ulong codeAddress,
int codePagesCount,
ProcessCreationFlags flags,
int resourceLimitHandle,
int systemResourcePagesCount)
{
Name = name;
Version = category;
TitleId = titleId;
CodeAddress = codeAddress;
CodePagesCount = codePagesCount;
MmuFlags = mmuFlags;
ResourceLimitHandle = resourceLimitHandle;
PersonalMmHeapPagesCount = personalMmHeapPagesCount;
Name = name;
Version = version;
TitleId = titleId;
CodeAddress = codeAddress;
CodePagesCount = codePagesCount;
Flags = flags;
ResourceLimitHandle = resourceLimitHandle;
SystemResourcePagesCount = systemResourcePagesCount;
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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