aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-03-12 01:04:52 -0300
committergdkchan <gab.dark.100@gmail.com>2018-03-12 01:14:12 -0300
commit7a27990faa557c5c93f52e5cb082d551ad119ed0 (patch)
treea0800fded014a4a6afe738e5a65a17bc78cf0c19
parent3aaa4717b6f7400bac862e589a1f345e70e78d56 (diff)
Allow more than one process, free resources on process dispose, implement SvcExitThread
-rw-r--r--ChocolArm64/AThread.cs29
-rw-r--r--ChocolArm64/ATranslator.cs8
-rw-r--r--ChocolArm64/Instruction/AInstEmitException.cs16
-rw-r--r--ChocolArm64/State/AThreadState.cs2
-rw-r--r--Ryujinx.Core/Hid/Hid.cs30
-rw-r--r--Ryujinx.Core/Logging.cs7
-rw-r--r--Ryujinx.Core/OsHle/CondVar.cs2
-rw-r--r--Ryujinx.Core/OsHle/Handles/HDomain.cs58
-rw-r--r--Ryujinx.Core/OsHle/Handles/HNvMap.cs18
-rw-r--r--Ryujinx.Core/OsHle/Handles/HSharedMem.cs15
-rw-r--r--Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs63
-rw-r--r--Ryujinx.Core/OsHle/Homebrew.cs28
-rw-r--r--Ryujinx.Core/OsHle/Horizon.cs127
-rw-r--r--Ryujinx.Core/OsHle/IdDictionary.cs (renamed from Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs)57
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcHandler.cs75
-rw-r--r--Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs8
-rw-r--r--Ryujinx.Core/OsHle/Mutex.cs2
-rw-r--r--Ryujinx.Core/OsHle/Process.cs143
-rw-r--r--Ryujinx.Core/OsHle/ServiceCtx.cs3
-rw-r--r--Ryujinx.Core/OsHle/ServiceMgr.cs109
-rw-r--r--Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs2
-rw-r--r--Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs2
-rw-r--r--Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs5
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvFd.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/NvMap.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs264
-rw-r--r--Ryujinx.Core/OsHle/Services/ObjHelper.cs4
-rw-r--r--Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs12
-rw-r--r--Ryujinx.Core/OsHle/Services/ServiceFactory.cs64
-rw-r--r--Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs4
-rw-r--r--Ryujinx.Core/OsHle/Services/Vi/Display.cs (renamed from Ryujinx.Core/OsHle/Display.cs)2
-rw-r--r--Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs24
-rw-r--r--Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs5
-rw-r--r--Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs63
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcHandler.cs33
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcMemory.cs28
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcSystem.cs21
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcThread.cs15
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs4
-rw-r--r--Ryujinx.Core/OsHle/Utilities/IdPool.cs53
-rw-r--r--Ryujinx.Core/Switch.cs19
-rw-r--r--Ryujinx.Graphics/Gal/IGalRenderer.cs1
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs32
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs5
-rw-r--r--Ryujinx.Tests/Cpu/CpuTest.cs2
46 files changed, 914 insertions, 586 deletions
diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs
index cec26817..62f9d2d3 100644
--- a/ChocolArm64/AThread.cs
+++ b/ChocolArm64/AThread.cs
@@ -14,43 +14,30 @@ namespace ChocolArm64
private ATranslator Translator;
- private ThreadPriority Priority;
-
private Thread Work;
public event EventHandler WorkFinished;
public int ThreadId => ThreadState.ThreadId;
- public bool IsAlive => Work.IsAlive;
-
- private bool IsExecuting;
+ private int IsExecuting;
- private object ExecuteLock;
-
- public AThread(ATranslator Translator, AMemory Memory, ThreadPriority Priority, long EntryPoint)
+ public AThread(ATranslator Translator, AMemory Memory, long EntryPoint)
{
this.Translator = Translator;
this.Memory = Memory;
- this.Priority = Priority;
this.EntryPoint = EntryPoint;
ThreadState = new AThreadState();
- ExecuteLock = new object();
- }
- public void StopExecution() => Translator.StopExecution();
+ ThreadState.Running = true;
+ }
public bool Execute()
{
- lock (ExecuteLock)
+ if (Interlocked.Exchange(ref IsExecuting, 1) == 1)
{
- if (IsExecuting)
- {
- return false;
- }
-
- IsExecuting = true;
+ return false;
}
Work = new Thread(delegate()
@@ -62,11 +49,11 @@ namespace ChocolArm64
WorkFinished?.Invoke(this, EventArgs.Empty);
});
- Work.Priority = Priority;
-
Work.Start();
return true;
}
+
+ public void StopExecution() => ThreadState.Running = false;
}
} \ No newline at end of file
diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs
index 1f4a922a..02c18efd 100644
--- a/ChocolArm64/ATranslator.cs
+++ b/ChocolArm64/ATranslator.cs
@@ -22,8 +22,6 @@ namespace ChocolArm64
public bool EnableCpuTrace { get; set; }
- private bool KeepRunning;
-
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
{
SubBlocks = new HashSet<long>();
@@ -38,12 +36,8 @@ namespace ChocolArm64
{
this.SymbolTable = new ConcurrentDictionary<long, string>();
}
-
- KeepRunning = true;
}
- internal void StopExecution() => KeepRunning = false;
-
internal void ExecuteSubroutine(AThread Thread, long Position)
{
do
@@ -70,7 +64,7 @@ namespace ChocolArm64
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
}
- while (Position != 0 && KeepRunning);
+ while (Position != 0 && Thread.ThreadState.Running);
}
internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
diff --git a/ChocolArm64/Instruction/AInstEmitException.cs b/ChocolArm64/Instruction/AInstEmitException.cs
index fe348edd..3964c949 100644
--- a/ChocolArm64/Instruction/AInstEmitException.cs
+++ b/ChocolArm64/Instruction/AInstEmitException.cs
@@ -34,6 +34,22 @@ namespace ChocolArm64.Instruction
Context.EmitCall(MthdInfo);
+ //Check if the thread should still be running, if it isn't then we return 0
+ //to force a return to the dispatcher and then exit the thread.
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
+ Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running));
+
+ AILLabel LblEnd = new AILLabel();
+
+ Context.Emit(OpCodes.Brtrue_S, LblEnd);
+
+ Context.EmitLdc_I8(0);
+
+ Context.Emit(OpCodes.Ret);
+
+ Context.MarkLabel(LblEnd);
+
if (Context.CurrBlock.Next != null)
{
Context.EmitLoadState(Context.CurrBlock.Next);
diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs
index d86f5bf9..ec8621b8 100644
--- a/ChocolArm64/State/AThreadState.cs
+++ b/ChocolArm64/State/AThreadState.cs
@@ -29,6 +29,8 @@ namespace ChocolArm64.State
public int ProcessId;
public int ThreadId;
+ public bool Running { get; set; }
+
public long TpidrEl0 { get; set; }
public long Tpidr { get; set; }
diff --git a/Ryujinx.Core/Hid/Hid.cs b/Ryujinx.Core/Hid/Hid.cs
index c287564d..f25a9437 100644
--- a/Ryujinx.Core/Hid/Hid.cs
+++ b/Ryujinx.Core/Hid/Hid.cs
@@ -63,17 +63,13 @@ namespace Ryujinx.Core.Input
private object ShMemLock;
- private long[] ShMemPositions;
+ private (AMemory, long)[] ShMemPositions;
- private AMemory Memory;
-
- public Hid(AMemory Memory)
+ public Hid()
{
- this.Memory = Memory;
-
ShMemLock = new object();
- ShMemPositions = new long[0];
+ ShMemPositions = new (AMemory, long)[0];
}
internal void ShMemMap(object sender, EventArgs e)
@@ -84,11 +80,11 @@ namespace Ryujinx.Core.Input
{
ShMemPositions = SharedMem.GetVirtualPositions();
- long BasePosition = ShMemPositions[ShMemPositions.Length - 1];
+ (AMemory Memory, long Position) ShMem = ShMemPositions[ShMemPositions.Length - 1];
- Logging.Info($"HID shared memory successfully mapped to 0x{BasePosition:x16}!");
+ Logging.Info($"HID shared memory successfully mapped to 0x{ShMem.Position:x16}!");
- Init(BasePosition);
+ Init(ShMem.Memory, ShMem.Position);
}
}
@@ -102,10 +98,11 @@ namespace Ryujinx.Core.Input
}
}
- private void Init(long BasePosition)
+ private void Init(AMemory Memory, long Position)
{
InitializeJoyconPair(
- BasePosition,
+ Memory,
+ Position,
JoyConColor.Body_Neon_Red,
JoyConColor.Buttons_Neon_Red,
JoyConColor.Body_Neon_Blue,
@@ -113,13 +110,14 @@ namespace Ryujinx.Core.Input
}
private void InitializeJoyconPair(
- long BasePosition,
+ AMemory Memory,
+ long Position,
JoyConColor LeftColorBody,
JoyConColor LeftColorButtons,
JoyConColor RightColorBody,
JoyConColor RightColorButtons)
{
- long BaseControllerOffset = BasePosition + HidControllersOffset + 8 * HidControllerSize;
+ long BaseControllerOffset = Position + HidControllersOffset + 8 * HidControllerSize;
HidControllerType Type =
HidControllerType.ControllerType_Handheld |
@@ -160,7 +158,7 @@ namespace Ryujinx.Core.Input
{
lock (ShMemLock)
{
- foreach (long Position in ShMemPositions)
+ foreach ((AMemory Memory, long Position) in ShMemPositions)
{
long ControllerOffset = Position + HidControllersOffset;
@@ -207,7 +205,7 @@ namespace Ryujinx.Core.Input
{
lock (ShMemLock)
{
- foreach (long Position in ShMemPositions)
+ foreach ((AMemory Memory, long Position) in ShMemPositions)
{
long TouchScreenOffset = Position + HidTouchScreenOffset;
diff --git a/Ryujinx.Core/Logging.cs b/Ryujinx.Core/Logging.cs
index d544a5d6..89064ccb 100644
--- a/Ryujinx.Core/Logging.cs
+++ b/Ryujinx.Core/Logging.cs
@@ -8,7 +8,8 @@ namespace Ryujinx.Core
{
public static class Logging
{
- private static Stopwatch ExecutionTime = new Stopwatch();
+ private static Stopwatch ExecutionTime;
+
private const string LogFileName = "Ryujinx.log";
private static bool EnableInfo = Config.LoggingEnableInfo;
@@ -23,6 +24,10 @@ namespace Ryujinx.Core
static Logging()
{
if (File.Exists(LogFileName)) File.Delete(LogFileName);
+
+ ExecutionTime = new Stopwatch();
+
+ ExecutionTime.Start();
}
public static string GetExecutionTime()
diff --git a/Ryujinx.Core/OsHle/CondVar.cs b/Ryujinx.Core/OsHle/CondVar.cs
index ac3ba574..f5fe3d29 100644
--- a/Ryujinx.Core/OsHle/CondVar.cs
+++ b/Ryujinx.Core/OsHle/CondVar.cs
@@ -4,7 +4,7 @@ using System.Threading;
namespace Ryujinx.Core.OsHle
{
- public class CondVar
+ class CondVar
{
private Process Process;
diff --git a/Ryujinx.Core/OsHle/Handles/HDomain.cs b/Ryujinx.Core/OsHle/Handles/HDomain.cs
index ca287a5f..ac99b03a 100644
--- a/Ryujinx.Core/OsHle/Handles/HDomain.cs
+++ b/Ryujinx.Core/OsHle/Handles/HDomain.cs
@@ -1,58 +1,48 @@
-using Ryujinx.Core.OsHle.Utilities;
using System;
-using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.Handles
{
- class HDomain : HSession
+ class HDomain : HSession, IDisposable
{
- private Dictionary<int, object> Objects;
-
- private IdPool ObjIds;
+ private IdDictionary Objects;
public HDomain(HSession Session) : base(Session)
{
- Objects = new Dictionary<int, object>();
-
- ObjIds = new IdPool();
+ Objects = new IdDictionary();
}
- public int GenerateObjectId(object Obj)
+ public int Add(object Obj)
{
- int Id = ObjIds.GenerateId();
-
- if (Id == -1)
- {
- throw new InvalidOperationException();
- }
-
- Objects.Add(Id, Obj);
+ return Objects.Add(Obj);
+ }
- return Id;
+ public bool Delete(int Id)
+ {
+ return Objects.Delete(Id);
}
- public void DeleteObject(int Id)
+ public object GetObject(int Id)
{
- if (Objects.TryGetValue(Id, out object Obj))
- {
- if (Obj is IDisposable DisposableObj)
- {
- DisposableObj.Dispose();
- }
+ return Objects.GetData(Id);
+ }
- ObjIds.DeleteId(Id);
- Objects.Remove(Id);
- }
+ public void Dispose()
+ {
+ Dispose(true);
}
- public object GetObject(int Id)
+ protected virtual void Dispose(bool Disposing)
{
- if (Objects.TryGetValue(Id, out object Obj))
+ if (Disposing)
{
- return Obj;
+ foreach (object Obj in Objects)
+ {
+ if (Obj is IDisposable DisposableObj)
+ {
+ DisposableObj.Dispose();
+ }
+ }
}
-
- return null;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HNvMap.cs b/Ryujinx.Core/OsHle/Handles/HNvMap.cs
deleted file mode 100644
index 09173730..00000000
--- a/Ryujinx.Core/OsHle/Handles/HNvMap.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Ryujinx.Core.OsHle.Handles
-{
- class HNvMap
- {
- public int Id { get; private set; }
- public int Size { get; private set; }
-
- public int Align { get; set; }
- public int Kind { get; set; }
- public long Address { get; set; }
-
- public HNvMap(int Id, int Size)
- {
- this.Id = Id;
- this.Size = Size;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
index eb173e96..b6bdc898 100644
--- a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
+++ b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
@@ -1,3 +1,4 @@
+using ChocolArm64.Memory;
using System;
using System.Collections.Generic;
@@ -5,37 +6,37 @@ namespace Ryujinx.Core.OsHle.Handles
{
class HSharedMem
{
- private List<long> Positions;
+ private List<(AMemory, long)> Positions;
public EventHandler<EventArgs> MemoryMapped;
public EventHandler<EventArgs> MemoryUnmapped;
public HSharedMem()
{
- Positions = new List<long>();
+ Positions = new List<(AMemory, long)>();
}
- public void AddVirtualPosition(long Position)
+ public void AddVirtualPosition(AMemory Memory, long Position)
{
lock (Positions)
{
- Positions.Add(Position);
+ Positions.Add((Memory, Position));
MemoryMapped?.Invoke(this, EventArgs.Empty);
}
}
- public void RemoveVirtualPosition(long Position)
+ public void RemoveVirtualPosition(AMemory Memory, long Position)
{
lock (Positions)
{
- Positions.Remove(Position);
+ Positions.Remove((Memory, Position));
MemoryUnmapped?.Invoke(this, EventArgs.Empty);
}
}
- public long[] GetVirtualPositions()
+ public (AMemory, long)[] GetVirtualPositions()
{
return Positions.ToArray();
}
diff --git a/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
new file mode 100644
index 00000000..1156e035
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
@@ -0,0 +1,63 @@
+using System;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+ class KProcessHandleTable : IDisposable
+ {
+ private IdDictionary Handles;
+
+ public KProcessHandleTable()
+ {
+ Handles = new IdDictionary();
+ }
+
+ public int OpenHandle(object Obj)
+ {
+ return Handles.Add(Obj);
+ }
+
+ public T GetData<T>(int Handle)
+ {
+ return Handles.GetData<T>(Handle);
+ }
+
+ public bool ReplaceData(int Id, object Data)
+ {
+ return Handles.ReplaceData(Id, Data);
+ }
+
+ public bool CloseHandle(int Handle)
+ {
+ object Data = Handles.GetData(Handle);
+
+ if (Data is HTransferMem TMem)
+ {
+ TMem.Memory.Manager.Reprotect(
+ TMem.Position,
+ TMem.Size,
+ TMem.Perm);
+ }
+
+ return Handles.Delete(Handle);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
+ {
+ foreach (object Obj in Handles)
+ {
+ if (Obj is IDisposable DisposableObj)
+ {
+ DisposableObj.Dispose();
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Homebrew.cs b/Ryujinx.Core/OsHle/Homebrew.cs
index e2e95e4d..2a717ca7 100644
--- a/Ryujinx.Core/OsHle/Homebrew.cs
+++ b/Ryujinx.Core/OsHle/Homebrew.cs
@@ -37,5 +37,33 @@ namespace Ryujinx.Core.OsHle
Position += 0x18;
}
+
+ public static string ReadHbAbiNextLoadPath(AMemory Memory, long Position)
+ {
+ string FileName = null;
+
+ while (true)
+ {
+ long Key = Memory.ReadInt64(Position);
+
+ if (Key == 2)
+ {
+ long Value0 = Memory.ReadInt64(Position + 0x08);
+ long Value1 = Memory.ReadInt64(Position + 0x10);
+
+ FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, (int)(Value1 - Value0));
+
+ break;
+ }
+ else if (Key == 0)
+ {
+ break;
+ }
+
+ Position += 0x18;
+ }
+
+ return FileName;
+ }
}
}
diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs
index c61e18e9..c3f8cd8b 100644
--- a/Ryujinx.Core/OsHle/Horizon.cs
+++ b/Ryujinx.Core/OsHle/Horizon.cs
@@ -1,33 +1,23 @@
using Ryujinx.Core.Loaders.Executables;
using Ryujinx.Core.OsHle.Handles;
-using Ryujinx.Core.OsHle.Utilities;
using System;
using System.Collections.Concurrent;
using System.IO;
namespace Ryujinx.Core.OsHle
{
- public class Horizon
+ public class Horizon : IDisposable
{
internal const int HidSize = 0x40000;
internal const int FontSize = 0x50;
- internal int HidHandle { get; private set; }
- internal int FontHandle { get; private set; }
-
- internal IdPool IdGen { get; private set; }
- internal IdPool NvMapIds { get; private set; }
-
- internal IdPoolWithObj Handles { get; private set; }
- internal IdPoolWithObj Fds { get; private set; }
- internal IdPoolWithObj Displays { get; private set; }
-
- public ConcurrentDictionary<long, Mutex> Mutexes { get; private set; }
- public ConcurrentDictionary<long, CondVar> CondVars { get; private set; }
+ internal ConcurrentDictionary<long, Mutex> Mutexes { get; private set; }
+ internal ConcurrentDictionary<long, CondVar> CondVars { get; private set; }
private ConcurrentDictionary<int, Process> Processes;
internal HSharedMem HidSharedMem;
+ internal HSharedMem FontSharedMem;
private Switch Ns;
@@ -35,25 +25,13 @@ namespace Ryujinx.Core.OsHle
{
this.Ns = Ns;
- IdGen = new IdPool();
- NvMapIds = new IdPool();
-
- Handles = new IdPoolWithObj();
- Fds = new IdPoolWithObj();
- Displays = new IdPoolWithObj();
-
Mutexes = new ConcurrentDictionary<long, Mutex>();
CondVars = new ConcurrentDictionary<long, CondVar>();
Processes = new ConcurrentDictionary<int, Process>();
- HidSharedMem = new HSharedMem();
-
- HidHandle = Handles.GenerateId(HidSharedMem);
-
- FontHandle = Handles.GenerateId(new HSharedMem());
-
- HidSharedMem.AddVirtualPosition(0);
+ HidSharedMem = new HSharedMem();
+ FontSharedMem = new HSharedMem();
}
public void LoadCart(string ExeFsDir, string RomFsFile = null)
@@ -63,9 +41,7 @@ namespace Ryujinx.Core.OsHle
Ns.VFs.LoadRomFs(RomFsFile);
}
- int ProcessId = IdGen.GenerateId();
-
- Process MainProcess = new Process(Ns, ProcessId);
+ Process MainProcess = MakeProcess();
void LoadNso(string FileName)
{
@@ -96,17 +72,13 @@ namespace Ryujinx.Core.OsHle
LoadNso("sdk");
MainProcess.Run();
-
- Processes.TryAdd(ProcessId, MainProcess);
}
public void LoadProgram(string FileName)
{
bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
- int ProcessId = IdGen.GenerateId();
-
- Process MainProcess = new Process(Ns, ProcessId);
+ Process MainProcess = MakeProcess();
using (FileStream Input = new FileStream(FileName, FileMode.Open))
{
@@ -117,34 +89,67 @@ namespace Ryujinx.Core.OsHle
MainProcess.SetEmptyArgs();
MainProcess.Run(IsNro);
-
- Processes.TryAdd(ProcessId, MainProcess);
}
- public void FinalizeAllProcesses()
+ private Process MakeProcess()
{
- foreach (Process Process in Processes.Values)
+ Process Process;
+
+ lock (Processes)
{
- Process.StopAllThreads();
- Process.Dispose();
+ int ProcessId = 0;
+
+ while (Processes.ContainsKey(ProcessId))
+ {
+ ProcessId++;
+ }
+
+ Process = new Process(Ns, ProcessId);
+
+ Processes.TryAdd(ProcessId, Process);
}
+
+ return Process;
}
- internal bool ExitProcess(int ProcessId)
+ internal void ExitProcess(int ProcessId)
{
- bool Success = Processes.TryRemove(ProcessId, out Process Process);
-
- if (Success)
+ if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
{
- Process.StopAllThreads();
+ string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
+
+ Logging.Info($"HbAbi NextLoadPath {NextNro}");
+
+ if (NextNro == string.Empty)
+ {
+ NextNro = "sdmc:/hbmenu.nro";
+ }
+
+ NextNro = NextNro.Replace("sdmc:", string.Empty);
+
+ NextNro = Ns.VFs.GetFullPath(Ns.VFs.GetSdCardPath(), NextNro);
+
+ if (File.Exists(NextNro))
+ {
+ //TODO: Those dictionaries shouldn't even exist,
+ //the Mutex and CondVar helper classes should be static.
+ Mutexes.Clear();
+ CondVars.Clear();
+
+ LoadProgram(NextNro);
+ }
}
- if (Processes.Count == 0)
+ if (Processes.TryRemove(ProcessId, out Process))
{
- Ns.OnFinish(EventArgs.Empty);
- }
+ Process.StopAllThreadsAsync();
+ Process.Dispose();
- return Success;
+ if (Processes.Count == 0)
+ {
+ Ns.OnFinish(EventArgs.Empty);
+ }
+ }
}
internal bool TryGetProcess(int ProcessId, out Process Process)
@@ -152,19 +157,21 @@ namespace Ryujinx.Core.OsHle
return Processes.TryGetValue(ProcessId, out Process);
}
- internal void CloseHandle(int Handle)
+ public void Dispose()
{
- object HndData = Handles.GetData<object>(Handle);
+ Dispose(true);
+ }
- if (HndData is HTransferMem TransferMem)
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
{
- TransferMem.Memory.Manager.Reprotect(
- TransferMem.Position,
- TransferMem.Size,
- TransferMem.Perm);
+ foreach (Process Process in Processes.Values)
+ {
+ Process.StopAllThreadsAsync();
+ Process.Dispose();
+ }
}
-
- Handles.Delete(Handle);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs b/Ryujinx.Core/OsHle/IdDictionary.cs
index f0a339df..0b909246 100644
--- a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs
+++ b/Ryujinx.Core/OsHle/IdDictionary.cs
@@ -3,31 +3,40 @@ using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
-namespace Ryujinx.Core.OsHle.Utilities
+namespace Ryujinx.Core.OsHle
{
- class IdPoolWithObj : IEnumerable<KeyValuePair<int, object>>
+ class IdDictionary : IEnumerable<object>
{
- private IdPool Ids;
-
private ConcurrentDictionary<int, object> Objs;
- public IdPoolWithObj()
- {
- Ids = new IdPool();
+ private int FreeIdHint = 1;
+ public IdDictionary()
+ {
Objs = new ConcurrentDictionary<int, object>();
}
- public int GenerateId(object Data)
+ public int Add(object Data)
{
- int Id = Ids.GenerateId();
+ if (Objs.TryAdd(FreeIdHint, Data))
+ {
+ return FreeIdHint++;
+ }
- if (Id == -1 || !Objs.TryAdd(Id, Data))
+ return AddSlow(Data);
+ }
+
+ private int AddSlow(object Data)
+ {
+ for (int Id = 1; Id < int.MaxValue; Id++)
{
- throw new InvalidOperationException();
+ if (Objs.TryAdd(Id, Data))
+ {
+ return Id;
+ }
}
- return Id;
+ throw new InvalidOperationException();
}
public bool ReplaceData(int Id, object Data)
@@ -42,6 +51,16 @@ namespace Ryujinx.Core.OsHle.Utilities
return false;
}
+ public object GetData(int Id)
+ {
+ if (Objs.TryGetValue(Id, out object Data))
+ {
+ return Data;
+ }
+
+ return null;
+ }
+
public T GetData<T>(int Id)
{
if (Objs.TryGetValue(Id, out object Data) && Data is T)
@@ -52,7 +71,7 @@ namespace Ryujinx.Core.OsHle.Utilities
return default(T);
}
- public void Delete(int Id)
+ public bool Delete(int Id)
{
if (Objs.TryRemove(Id, out object Obj))
{
@@ -61,18 +80,22 @@ namespace Ryujinx.Core.OsHle.Utilities
DisposableObj.Dispose();
}
- Ids.DeleteId(Id);
+ FreeIdHint = Id;
+
+ return true;
}
+
+ return false;
}
- IEnumerator<KeyValuePair<int, object>> IEnumerable<KeyValuePair<int, object>>.GetEnumerator()
+ IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
- return Objs.GetEnumerator();
+ return Objs.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
- return Objs.GetEnumerator();
+ return Objs.Values.GetEnumerator();
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
index 2495d701..f2179a96 100644
--- a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
+++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
@@ -13,6 +13,7 @@ namespace Ryujinx.Core.OsHle.Ipc
public static void IpcCall(
Switch Ns,
+ Process Process,
AMemory Memory,
HSession Session,
IpcMessage Request,
@@ -60,7 +61,7 @@ namespace Ryujinx.Core.OsHle.Ipc
}
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
{
- Dom.DeleteObject(Request.DomObjId);
+ Dom.Delete(Request.DomObjId);
Response = FillResponse(Response, 0);
@@ -100,6 +101,7 @@ namespace Ryujinx.Core.OsHle.Ipc
ServiceCtx Context = new ServiceCtx(
Ns,
+ Process,
Memory,
Session,
Request,
@@ -124,15 +126,43 @@ namespace Ryujinx.Core.OsHle.Ipc
switch (CmdId)
{
- case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break;
- case 3: Request = IpcQueryBufferPointerSize(Response); break;
- case 2: //IpcDuplicateSession, differences is unknown.
- case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break;
+ case 0:
+ {
+ HDomain Dom = new HDomain(Session);
+
+ Process.HandleTable.ReplaceData(HndId, Dom);
+
+ Request = FillResponse(Response, 0, Dom.Add(Dom));
+
+ break;
+ }
+
+ case 3:
+ {
+ Request = FillResponse(Response, 0, 0x500);
+
+ break;
+ }
+
+ //TODO: Whats the difference between IpcDuplicateSession/Ex?
+ case 2:
+ case 4:
+ {
+ int Unknown = ReqReader.ReadInt32();
+
+ int Handle = Process.HandleTable.OpenHandle(Session);
+
+ Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
+
+ Request = FillResponse(Response, 0);
+
+ break;
+ }
default: throw new NotImplementedException(CmdId.ToString());
}
}
- else if (Request.Type == IpcMessageType.Unknown2)
+ else if (Request.Type == IpcMessageType.CloseSession)
{
//TODO
}
@@ -145,39 +175,6 @@ namespace Ryujinx.Core.OsHle.Ipc
}
}
- private static IpcMessage IpcConvertSessionToDomain(
- Switch Ns,
- HSession Session,
- IpcMessage Response,
- int HndId)
- {
- HDomain Dom = new HDomain(Session);
-
- Ns.Os.Handles.ReplaceData(HndId, Dom);
-
- return FillResponse(Response, 0, Dom.GenerateObjectId(Dom));
- }
-
- private static IpcMessage IpcDuplicateSessionEx(
- Switch Ns,
- HSession Session,
- IpcMessage Response,
- BinaryReader ReqReader)
- {
- int Unknown = ReqReader.ReadInt32();
-
- int Handle = Ns.Os.Handles.GenerateId(Session);
-
- Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
-
- return FillResponse(Response, 0);
- }
-
- private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response)
- {
- return FillResponse(Response, 0, 0x500);
- }
-
private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
{
using (MemoryStream MS = new MemoryStream())
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
index 8027508d..560af41e 100644
--- a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
+++ b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
@@ -2,9 +2,9 @@ namespace Ryujinx.Core.OsHle.Ipc
{
enum IpcMessageType
{
- Response = 0,
- Unknown2 = 2,
- Request = 4,
- Control = 5
+ Response = 0,
+ CloseSession = 2,
+ Request = 4,
+ Control = 5
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Mutex.cs b/Ryujinx.Core/OsHle/Mutex.cs
index c95ed771..c619e121 100644
--- a/Ryujinx.Core/OsHle/Mutex.cs
+++ b/Ryujinx.Core/OsHle/Mutex.cs
@@ -4,7 +4,7 @@ using System.Threading;
namespace Ryujinx.Core.OsHle
{
- public class Mutex
+ class Mutex
{
private const int MutexHasListenersMask = 0x40000000;
diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs
index a919f1af..a8719e1c 100644
--- a/Ryujinx.Core/OsHle/Process.cs
+++ b/Ryujinx.Core/OsHle/Process.cs
@@ -9,25 +9,32 @@ using Ryujinx.Core.OsHle.Svc;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Threading;
namespace Ryujinx.Core.OsHle
{
- public class Process : IDisposable
+ class Process : IDisposable
{
- private const int TlsSize = 0x200;
- private const int TotalTlsSlots = 32;
+ private const int TlsSize = 0x200;
+ private const int TotalTlsSlots = 32;
private Switch Ns;
+ public bool NeedsHbAbi { get; private set; }
+
+ public long HbAbiDataPosition { get; private set; }
+
public int ProcessId { get; private set; }
private ATranslator Translator;
public AMemory Memory { get; private set; }
+ public ServiceMgr Services { get; private set; }
+
public KProcessScheduler Scheduler { get; private set; }
+ public KProcessHandleTable HandleTable { get; private set; }
+
private SvcHandler SvcHandler;
private ConcurrentDictionary<int, AThread> TlsSlots;
@@ -40,14 +47,22 @@ namespace Ryujinx.Core.OsHle
private long ImageBase;
+ private bool ShouldDispose;
+
+ private bool Disposed;
+
public Process(Switch Ns, int ProcessId)
{
this.Ns = Ns;
this.ProcessId = ProcessId;
- Memory = Ns.Memory;
+ Memory = new AMemory();
- Scheduler = new KProcessScheduler();
+ Services = new ServiceMgr();
+
+ HandleTable = new KProcessHandleTable();
+
+ Scheduler = new KProcessScheduler();
SvcHandler = new SvcHandler(Ns, this);
@@ -67,6 +82,11 @@ namespace Ryujinx.Core.OsHle
public void LoadProgram(IExecutable Program)
{
+ if (Disposed)
+ {
+ throw new ObjectDisposedException(nameof(Process));
+ }
+
Logging.Info($"Image base at 0x{ImageBase:x16}.");
Executable Executable = new Executable(Program, Memory, ImageBase);
@@ -78,11 +98,19 @@ namespace Ryujinx.Core.OsHle
public void SetEmptyArgs()
{
+ //TODO: This should be part of Run.
ImageBase += AMemoryMgr.PageSize;
}
- public bool Run(bool UseHbAbi = false)
+ public bool Run(bool NeedsHbAbi = false)
{
+ if (Disposed)
+ {
+ throw new ObjectDisposedException(nameof(Process));
+ }
+
+ this.NeedsHbAbi = NeedsHbAbi;
+
if (Executables.Count == 0)
{
return false;
@@ -102,11 +130,11 @@ namespace Ryujinx.Core.OsHle
return false;
}
- MainThread = Ns.Os.Handles.GetData<HThread>(Handle);
+ MainThread = HandleTable.GetData<HThread>(Handle);
- if (UseHbAbi)
+ if (NeedsHbAbi)
{
- long HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd);
+ HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd);
Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle);
@@ -124,22 +152,21 @@ namespace Ryujinx.Core.OsHle
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
}
- public void StopAllThreads()
+ public void StopAllThreadsAsync()
{
+ if (Disposed)
+ {
+ throw new ObjectDisposedException(nameof(Process));
+ }
+
if (MainThread != null)
{
- while (MainThread.Thread.IsAlive)
- {
- MainThread.Thread.StopExecution();
- }
+ MainThread.Thread.StopExecution();
}
foreach (AThread Thread in TlsSlots.Values)
{
- while (Thread.IsAlive)
- {
- Thread.StopExecution();
- }
+ Thread.StopExecution();
}
}
@@ -150,49 +177,26 @@ namespace Ryujinx.Core.OsHle
int Priority,
int ProcessorId)
{
- ThreadPriority ThreadPrio;
-
- if (Priority < 12)
+ if (Disposed)
{
- ThreadPrio = ThreadPriority.Highest;
- }
- else if (Priority < 24)
- {
- ThreadPrio = ThreadPriority.AboveNormal;
- }
- else if (Priority < 36)
- {
- ThreadPrio = ThreadPriority.Normal;
- }
- else if (Priority < 48)
- {
- ThreadPrio = ThreadPriority.BelowNormal;
- }
- else
- {
- ThreadPrio = ThreadPriority.Lowest;
+ throw new ObjectDisposedException(nameof(Process));
}
- AThread Thread = new AThread(GetTranslator(), Memory, ThreadPrio, EntryPoint);
+ AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
- int Handle = Ns.Os.Handles.GenerateId(ThreadHnd);
-
- int TlsSlot = GetFreeTlsSlot(Thread);
+ int Handle = HandleTable.OpenHandle(ThreadHnd);
- if (TlsSlot == -1 || Handle == -1)
- {
- return -1;
- }
+ int ThreadId = GetFreeTlsSlot(Thread);
- long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * TlsSize;
+ long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
Thread.ThreadState.Break += BreakHandler;
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
Thread.ThreadState.Undefined += UndefinedHandler;
Thread.ThreadState.ProcessId = ProcessId;
- Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId();
+ Thread.ThreadState.ThreadId = ThreadId;
Thread.ThreadState.Tpidr = Tpidr;
Thread.ThreadState.X0 = (ulong)ArgsPtr;
Thread.ThreadState.X1 = (ulong)Handle;
@@ -224,7 +228,7 @@ namespace Ryujinx.Core.OsHle
foreach (Executable Exe in Executables)
{
foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
- {
+ {
SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
}
}
@@ -274,16 +278,28 @@ namespace Ryujinx.Core.OsHle
}
}
- return -1;
+ throw new InvalidOperationException();
}
private void ThreadFinished(object sender, EventArgs e)
{
if (sender is AThread Thread)
{
+ Logging.Info($"Thread {Thread.ThreadId} exiting...");
+
TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _);
+ }
- Ns.Os.IdGen.DeleteId(Thread.ThreadId);
+ if (TlsSlots.Count == 0)
+ {
+ if (ShouldDispose)
+ {
+ Dispose();
+ }
+
+ Logging.Info($"No threads running, now exiting Process {ProcessId}...");
+
+ Ns.Os.ExitProcess(ProcessId);
}
}
@@ -309,9 +325,30 @@ namespace Ryujinx.Core.OsHle
protected virtual void Dispose(bool Disposing)
{
- if (Disposing)
+ if (Disposing && !Disposed)
{
+ //If there is still some thread running, disposing the objects is not
+ //safe as the thread may try to access those resources. Instead, we set
+ //the flag to have the Process disposed when all threads finishes.
+ //Note: This may not happen if the guest code gets stuck on a infinite loop.
+ if (TlsSlots.Count > 0)
+ {
+ ShouldDispose = true;
+
+ Logging.Info($"Process {ProcessId} waiting all threads terminate...");
+
+ return;
+ }
+
+ Disposed = true;
+
+ Services.Dispose();
+ HandleTable.Dispose();
Scheduler.Dispose();
+ SvcHandler.Dispose();
+ Memory.Dispose();
+
+ Logging.Info($"Process {ProcessId} exiting...");
}
}
}
diff --git a/Ryujinx.Core/OsHle/ServiceCtx.cs b/Ryujinx.Core/OsHle/ServiceCtx.cs
index 31ecce3d..60c378d5 100644
--- a/Ryujinx.Core/OsHle/ServiceCtx.cs
+++ b/Ryujinx.Core/OsHle/ServiceCtx.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Core.OsHle
class ServiceCtx
{
public Switch Ns { get; private set; }
+ public Process Process { get; private set; }
public AMemory Memory { get; private set; }
public HSession Session { get; private set; }
public IpcMessage Request { get; private set; }
@@ -17,6 +18,7 @@ namespace Ryujinx.Core.OsHle
public ServiceCtx(
Switch Ns,
+ Process Process,
AMemory Memory,
HSession Session,
IpcMessage Request,
@@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle
BinaryWriter ResponseData)
{
this.Ns = Ns;
+ this.Process = Process;
this.Memory = Memory;
this.Session = Session;
this.Request = Request;
diff --git a/Ryujinx.Core/OsHle/ServiceMgr.cs b/Ryujinx.Core/OsHle/ServiceMgr.cs
new file mode 100644
index 00000000..cbf6386f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/ServiceMgr.cs
@@ -0,0 +1,109 @@
+using Ryujinx.Core.OsHle.IpcServices;
+using Ryujinx.Core.OsHle.IpcServices.Acc;
+using Ryujinx.Core.OsHle.IpcServices.Am;
+using Ryujinx.Core.OsHle.IpcServices.Apm;
+using Ryujinx.Core.OsHle.IpcServices.Aud;
+using Ryujinx.Core.OsHle.IpcServices.Bsd;
+using Ryujinx.Core.OsHle.IpcServices.Friend;
+using Ryujinx.Core.OsHle.IpcServices.FspSrv;
+using Ryujinx.Core.OsHle.IpcServices.Hid;
+using Ryujinx.Core.OsHle.IpcServices.Lm;
+using Ryujinx.Core.OsHle.IpcServices.Nifm;
+using Ryujinx.Core.OsHle.IpcServices.Ns;
+using Ryujinx.Core.OsHle.IpcServices.NvServices;
+using Ryujinx.Core.OsHle.IpcServices.Pctl;
+using Ryujinx.Core.OsHle.IpcServices.Pl;
+using Ryujinx.Core.OsHle.IpcServices.Set;
+using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
+using Ryujinx.Core.OsHle.IpcServices.Sm;
+using Ryujinx.Core.OsHle.IpcServices.Ssl;
+using Ryujinx.Core.OsHle.IpcServices.Time;
+using Ryujinx.Core.OsHle.IpcServices.Vi;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle
+{
+ class ServiceMgr : IDisposable
+ {
+ private Dictionary<string, IIpcService> Services;
+
+ public ServiceMgr()
+ {
+ Services = new Dictionary<string, IIpcService>();
+ }
+
+ public IIpcService GetService(string Name)
+ {
+ lock (Services)
+ {
+ if (!Services.TryGetValue(Name, out IIpcService Service))
+ {
+ switch (Name)
+ {
+ case "acc:u0": Service = new ServiceAcc(); break;
+ case "aoc:u": Service = new ServiceNs(); break;
+ case "apm": Service = new ServiceApm(); break;
+ case "apm:p": Service = new ServiceApm(); break;
+ case "appletOE": Service = new ServiceAppletOE(); break;
+ case "audout:u": Service = new ServiceAudOut(); break;
+ case "audren:u": Service = new ServiceAudRen(); break;
+ case "bsd:u": Service = new ServiceBsd(); break;
+ case "friend:a": Service = new ServiceFriend(); break;
+ case "fsp-srv": Service = new ServiceFspSrv(); break;
+ case "hid": Service = new ServiceHid(); break;
+ case "lm": Service = new ServiceLm(); break;
+ case "nifm:u": Service = new ServiceNifm(); break;
+ case "nvdrv": Service = new ServiceNvDrv(); break;
+ case "nvdrv:a": Service = new ServiceNvDrv(); break;
+ case "pctl:a": Service = new ServicePctl(); break;
+ case "pl:u": Service = new ServicePl(); break;
+ case "set": Service = new ServiceSet(); break;
+ case "set:sys": Service = new ServiceSetSys(); break;
+ case "sfdnsres": Service = new ServiceSfdnsres(); break;
+ case "sm:": Service = new ServiceSm(); break;
+ case "ssl": Service = new ServiceSsl(); break;
+ case "time:s": Service = new ServiceTime(); break;
+ case "time:u": Service = new ServiceTime(); break;
+ case "vi:m": Service = new ServiceVi(); break;
+ case "vi:s": Service = new ServiceVi(); break;
+ case "vi:u": Service = new ServiceVi(); break;
+ }
+
+ if (Service == null)
+ {
+ throw new NotImplementedException(Name);
+ }
+
+ Services.Add(Name, Service);
+ }
+
+ return Service;
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
+ {
+ lock (Services)
+ {
+ foreach (IIpcService Service in Services.Values)
+ {
+ if (Service is IDisposable DisposableSrv)
+ {
+ DisposableSrv.Dispose();
+ }
+ }
+
+ Services.Clear();
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
index c58d9e80..2312920f 100644
--- a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
+++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
@@ -139,7 +139,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long RegisterBufferEvent(ServiceCtx Context)
{
- int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+ int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
index bfde0b65..4d29371f 100644
--- a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
+++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
@@ -56,7 +56,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long QuerySystemEvent(ServiceCtx Context)
{
- int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+ int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
diff --git a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
index d22e0ff2..ef437c02 100644
--- a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
+++ b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
@@ -10,21 +10,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
- private HSharedMem Handle;
+ private HSharedMem HidSharedMem;
- public IAppletResource(HSharedMem Handle)
+ public IAppletResource(HSharedMem HidSharedMem)
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, GetSharedMemoryHandle }
};
- this.Handle = Handle;
+ this.HidSharedMem = HidSharedMem;
}
- public static long GetSharedMemoryHandle(ServiceCtx Context)
+ public long GetSharedMemoryHandle(ServiceCtx Context)
{
- Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle);
+ int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem);
+
+ Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0;
}
diff --git a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
index cc30a771..b1f93072 100644
--- a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
+++ b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
@@ -32,9 +31,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
public long CreateAppletResource(ServiceCtx Context)
{
- HSharedMem HidHndData = Context.Ns.Os.Handles.GetData<HSharedMem>(Context.Ns.Os.HidHandle);
-
- MakeObject(Context, new IAppletResource(HidHndData));
+ MakeObject(Context, new IAppletResource(Context.Ns.Os.HidSharedMem));
return 0;
}
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs b/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs
new file mode 100644
index 00000000..dbce74ad
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.IpcServices.NvServices
+{
+ class NvFd
+ {
+ public string Name { get; private set; }
+
+ public NvFd(string Name)
+ {
+ this.Name = Name;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
new file mode 100644
index 00000000..ca844f9f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.IpcServices.NvServices
+{
+ class NvMap
+ {
+ public int Handle;
+ public int Id;
+ public int Size;
+ public int Align;
+ public int Kind;
+ public long Address;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
index 3c0c46fe..67ad4491 100644
--- a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
+++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
@@ -1,5 +1,4 @@
using ChocolArm64.Memory;
-using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.Utilities;
using Ryujinx.Graphics.Gpu;
@@ -12,41 +11,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{
private delegate long ServiceProcessIoctl(ServiceCtx Context);
- private static Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds =
- new Dictionary<(string, int), ServiceProcessIoctl>()
- {
- { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel },
- { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace },
- { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx },
- { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions },
- { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx },
- { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig },
- { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait },
- { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize },
- { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo },
- { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics },
- { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks },
- { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask },
- { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData },
- { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap },
- { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo },
- { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx },
- { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind },
- { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier },
- { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority },
- { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 },
- { ("/dev/nvmap", 0x0101), NvMapIocCreate },
- { ("/dev/nvmap", 0x0103), NvMapIocFromId },
- { ("/dev/nvmap", 0x0104), NvMapIocAlloc },
- { ("/dev/nvmap", 0x0105), NvMapIocFree },
- { ("/dev/nvmap", 0x0109), NvMapIocParam },
- { ("/dev/nvmap", 0x010e), NvMapIocGetId },
- };
-
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+ private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
+
+ private IdDictionary Fds;
+
+ private IdDictionary NvMaps;
+ private IdDictionary NvMapsById;
+
public ServiceNvDrv()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
@@ -58,15 +33,50 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ 4, QueryEvent },
{ 8, SetClientPid },
};
+
+ IoctlCmds = new Dictionary<(string, int), ServiceProcessIoctl>()
+ {
+ { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel },
+ { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace },
+ { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx },
+ { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions },
+ { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx },
+ { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig },
+ { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait },
+ { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize },
+ { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo },
+ { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics },
+ { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks },
+ { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask },
+ { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData },
+ { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap },
+ { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo },
+ { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx },
+ { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind },
+ { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier },
+ { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority },
+ { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 },
+ { ("/dev/nvmap", 0x0101), NvMapIocCreate },
+ { ("/dev/nvmap", 0x0103), NvMapIocFromId },
+ { ("/dev/nvmap", 0x0104), NvMapIocAlloc },
+ { ("/dev/nvmap", 0x0105), NvMapIocFree },
+ { ("/dev/nvmap", 0x0109), NvMapIocParam },
+ { ("/dev/nvmap", 0x010e), NvMapIocGetId },
+ };
+
+ Fds = new IdDictionary();
+
+ NvMaps = new IdDictionary();
+ NvMapsById = new IdDictionary();
}
- public static long Open(ServiceCtx Context)
+ public long Open(ServiceCtx Context)
{
long NamePtr = Context.Request.SendBuff[0].Position;
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
- int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name));
+ int Fd = Fds.Add(new NvFd(Name));
Context.ResponseData.Write(Fd);
Context.ResponseData.Write(0);
@@ -74,12 +84,12 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- public static long Ioctl(ServiceCtx Context)
+ public long Ioctl(ServiceCtx Context)
{
int Fd = Context.RequestData.ReadInt32();
int Cmd = Context.RequestData.ReadInt32() & 0xffff;
- FileDesc FdData = Context.Ns.Os.Fds.GetData<FileDesc>(Fd);
+ NvFd FdData = Fds.GetData<NvFd>(Fd);
long Position = Context.Request.GetSendBuffPtr();
@@ -95,18 +105,18 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
}
}
- public static long Close(ServiceCtx Context)
+ public long Close(ServiceCtx Context)
{
int Fd = Context.RequestData.ReadInt32();
- Context.Ns.Os.Fds.Delete(Fd);
+ Fds.Delete(Fd);
Context.ResponseData.Write(0);
return 0;
}
- public static long Initialize(ServiceCtx Context)
+ public long Initialize(ServiceCtx Context)
{
long TransferMemSize = Context.RequestData.ReadInt64();
int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
@@ -116,7 +126,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- public static long QueryEvent(ServiceCtx Context)
+ public long QueryEvent(ServiceCtx Context)
{
int Fd = Context.RequestData.ReadInt32();
int EventId = Context.RequestData.ReadInt32();
@@ -128,7 +138,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- public static long SetClientPid(ServiceCtx Context)
+ public long SetClientPid(ServiceCtx Context)
{
long Pid = Context.RequestData.ReadInt64();
@@ -137,7 +147,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuAsIoctlBindChannel(ServiceCtx Context)
+ private long NvGpuAsIoctlBindChannel(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -146,7 +156,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
+ private long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -172,7 +182,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
+ private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -186,18 +196,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
long MapSize = Reader.ReadInt64();
long Offset = Reader.ReadInt64();
- HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+ if (Handle == 0)
+ {
+ //Handle 0 is valid here, but it refers to something else.
+ //TODO: Figure out what, for now just return success.
+ return 0;
+ }
+
+ NvMap Map = NvMaps.GetData<NvMap>(Handle);
- if (NvMap != null)
+ if (Map == null)
{
- if ((Flags & 1) != 0)
- {
- Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size);
- }
- else
- {
- Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size);
- }
+ Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+
+ return -1; //TODO: Corrent error code.
+ }
+
+ if ((Flags & 1) != 0)
+ {
+ Offset = Context.Ns.Gpu.MapMemory(Map.Address, Offset, Map.Size);
+ }
+ else
+ {
+ Offset = Context.Ns.Gpu.MapMemory(Map.Address, Map.Size);
}
Context.Memory.WriteInt64(Position + 0x20, Offset);
@@ -205,7 +226,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
+ private long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -235,7 +256,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
+ private long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -252,7 +273,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
+ private long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -267,7 +288,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvHostIoctlCtrlEventWait(ServiceCtx Context)
+ private long NvHostIoctlCtrlEventWait(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -283,7 +304,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
+ private long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -292,7 +313,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
+ private long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -312,7 +333,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
+ private long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -374,7 +395,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
+ private long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -388,7 +409,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
+ private long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -398,14 +419,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelSetUserData(ServiceCtx Context)
+ private long NvMapIoctlChannelSetUserData(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
return 0;
}
- private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
+ private long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -414,7 +435,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
+ private long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -453,7 +474,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
+ private long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -465,7 +486,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelZcullBind(ServiceCtx Context)
+ private long NvMapIoctlChannelZcullBind(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -478,7 +499,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
+ private long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -492,7 +513,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelSetPriority(ServiceCtx Context)
+ private long NvMapIoctlChannelSetPriority(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -501,7 +522,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
+ private long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -521,47 +542,46 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIocCreate(ServiceCtx Context)
+ private long NvMapIocCreate(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
int Size = Context.Memory.ReadInt32(Position);
- int Id = Context.Ns.Os.NvMapIds.GenerateId();
+ NvMap Map = new NvMap() { Size = Size };
+
+ Map.Handle = NvMaps.Add(Map);
- int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size));
+ Map.Id = NvMapsById.Add(Map);
- Context.Memory.WriteInt32(Position + 4, Handle);
+ Context.Memory.WriteInt32(Position + 4, Map.Handle);
- Logging.Info($"NvMap {Id} created with size {Size:x8}!");
+ Logging.Info($"NvMap {Map.Id} created with size {Size:x8}!");
return 0;
}
- private static long NvMapIocFromId(ServiceCtx Context)
+ private long NvMapIocFromId(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
int Id = Context.Memory.ReadInt32(Position);
- int Handle = -1;
+ NvMap Map = NvMapsById.GetData<NvMap>(Id);
- foreach (KeyValuePair<int, object> KV in Context.Ns.Os.Handles)
+ if (Map == null)
{
- if (KV.Value is HNvMap NvMap && NvMap.Id == Id)
- {
- Handle = KV.Key;
-
- break;
- }
+ Logging.Warn($"Trying to use invalid NvMap Id {Id}!");
+
+ return -1; //TODO: Corrent error code.
}
- Context.Memory.WriteInt32(Position + 4, Handle);
+ Context.Memory.WriteInt32(Position + 4, Map.Handle);
return 0;
}
- private static long NvMapIocAlloc(ServiceCtx Context)
+ private long NvMapIocAlloc(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -574,38 +594,49 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
byte Kind = (byte)Reader.ReadInt64();
long Addr = Reader.ReadInt64();
- HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+ NvMap Map = NvMaps.GetData<NvMap>(Handle);
- if (NvMap != null)
+ if (Map == null)
{
- NvMap.Address = Addr;
- NvMap.Align = Align;
- NvMap.Kind = Kind;
+ Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+
+ return -1; //TODO: Corrent error code.
}
+ Map.Address = Addr;
+ Map.Align = Align;
+ Map.Kind = Kind;
+
return 0;
}
- private static long NvMapIocFree(ServiceCtx Context)
+ private long NvMapIocFree(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
MemReader Reader = new MemReader(Context.Memory, Position);
MemWriter Writer = new MemWriter(Context.Memory, Position + 8);
- int Handle = Reader.ReadInt32();
- int Padding = Reader.ReadInt32();
+ int Handle = Reader.ReadInt32();
+ int Padding = Reader.ReadInt32();
- HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+ NvMap Map = NvMaps.GetData<NvMap>(Handle);
+
+ if (Map == null)
+ {
+ Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+
+ return -1; //TODO: Corrent error code.
+ }
Writer.WriteInt64(0);
- Writer.WriteInt32(NvMap.Size);
+ Writer.WriteInt32(Map.Size);
Writer.WriteInt32(0);
return 0;
}
- private static long NvMapIocParam(ServiceCtx Context)
+ private long NvMapIocParam(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
@@ -614,16 +645,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32();
int Param = Reader.ReadInt32();
- HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+ NvMap Map = NvMaps.GetData<NvMap>(Handle);
+
+ if (Map == null)
+ {
+ Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+
+ return -1; //TODO: Corrent error code.
+ }
int Response = 0;
-
+
switch (Param)
{
- case 1: Response = NvMap.Size; break;
- case 2: Response = NvMap.Align; break;
- case 4: Response = 0x40000000; break;
- case 5: Response = NvMap.Kind; break;
+ case 1: Response = Map.Size; break;
+ case 2: Response = Map.Align; break;
+ case 4: Response = 0x40000000; break;
+ case 5: Response = Map.Kind; break;
}
Context.Memory.WriteInt32(Position + 8, Response);
@@ -631,17 +669,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
- private static long NvMapIocGetId(ServiceCtx Context)
+ private long NvMapIocGetId(ServiceCtx Context)
{
long Position = Context.Request.GetSendBuffPtr();
int Handle = Context.Memory.ReadInt32(Position + 4);
- HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+ NvMap Map = NvMaps.GetData<NvMap>(Handle);
+
+ if (Map == null)
+ {
+ Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+
+ return -1; //TODO: Corrent error code.
+ }
- Context.Memory.WriteInt32(Position, NvMap.Id);
+ Context.Memory.WriteInt32(Position, Map.Id);
return 0;
}
+
+ public NvMap GetNvMap(int Handle)
+ {
+ return NvMaps.GetData<NvMap>(Handle);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/ObjHelper.cs b/Ryujinx.Core/OsHle/Services/ObjHelper.cs
index ff71838a..89d986ae 100644
--- a/Ryujinx.Core/OsHle/Services/ObjHelper.cs
+++ b/Ryujinx.Core/OsHle/Services/ObjHelper.cs
@@ -9,13 +9,13 @@ namespace Ryujinx.Core.OsHle.IpcServices
{
if (Context.Session is HDomain Dom)
{
- Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj));
+ Context.Response.ResponseObjIds.Add(Dom.Add(Obj));
}
else
{
HSessionObj HndData = new HSessionObj(Context.Session, Obj);
- int VHandle = Context.Ns.Os.Handles.GenerateId(HndData);
+ int VHandle = Context.Process.HandleTable.OpenHandle(HndData);
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
}
diff --git a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
index abc34ed2..bb795f3f 100644
--- a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
+++ b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
@@ -20,30 +20,32 @@ namespace Ryujinx.Core.OsHle.IpcServices.Pl
};
}
- public static long GetLoadState(ServiceCtx Context)
+ public long GetLoadState(ServiceCtx Context)
{
Context.ResponseData.Write(1); //Loaded
return 0;
}
- public static long GetFontSize(ServiceCtx Context)
+ public long GetFontSize(ServiceCtx Context)
{
Context.ResponseData.Write(Horizon.FontSize);
return 0;
}
- public static long GetSharedMemoryAddressOffset(ServiceCtx Context)
+ public long GetSharedMemoryAddressOffset(ServiceCtx Context)
{
Context.ResponseData.Write(0);
return 0;
}
- public static long GetSharedMemoryNativeHandle(ServiceCtx Context)
+ public long GetSharedMemoryNativeHandle(ServiceCtx Context)
{
- Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle);
+ int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.FontSharedMem);
+
+ Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0;
}
diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
deleted file mode 100644
index 2b855d25..00000000
--- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using Ryujinx.Core.OsHle.IpcServices.Acc;
-using Ryujinx.Core.OsHle.IpcServices.Am;
-using Ryujinx.Core.OsHle.IpcServices.Apm;
-using Ryujinx.Core.OsHle.IpcServices.Aud;
-using Ryujinx.Core.OsHle.IpcServices.Bsd;
-using Ryujinx.Core.OsHle.IpcServices.Friend;
-using Ryujinx.Core.OsHle.IpcServices.FspSrv;
-using Ryujinx.Core.OsHle.IpcServices.Hid;
-using Ryujinx.Core.OsHle.IpcServices.Lm;
-using Ryujinx.Core.OsHle.IpcServices.Nifm;
-using Ryujinx.Core.OsHle.IpcServices.Ns;
-using Ryujinx.Core.OsHle.IpcServices.NvServices;
-using Ryujinx.Core.OsHle.IpcServices.Pctl;
-using Ryujinx.Core.OsHle.IpcServices.Pl;
-using Ryujinx.Core.OsHle.IpcServices.Set;
-using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
-using Ryujinx.Core.OsHle.IpcServices.Sm;
-using Ryujinx.Core.OsHle.IpcServices.Ssl;
-using Ryujinx.Core.OsHle.IpcServices.Time;
-using Ryujinx.Core.OsHle.IpcServices.Vi;
-using System;
-
-namespace Ryujinx.Core.OsHle.IpcServices
-{
- static class ServiceFactory
- {
- public static IIpcService MakeService(string Name)
- {
- switch (Name)
- {
- case "acc:u0": return new ServiceAcc();
- case "aoc:u": return new ServiceNs();
- case "apm": return new ServiceApm();
- case "apm:p": return new ServiceApm();
- case "appletOE": return new ServiceAppletOE();
- case "audout:u": return new ServiceAudOut();
- case "audren:u": return new ServiceAudRen();
- case "bsd:s": return new ServiceBsd();
- case "bsd:u": return new ServiceBsd();
- case "friend:a": return new ServiceFriend();
- case "fsp-srv": return new ServiceFspSrv();
- case "hid": return new ServiceHid();
- case "lm": return new ServiceLm();
- case "nifm:u": return new ServiceNifm();
- case "nvdrv": return new ServiceNvDrv();
- case "nvdrv:a": return new ServiceNvDrv();
- case "pctl:a": return new ServicePctl();
- case "pl:u": return new ServicePl();
- case "set": return new ServiceSet();
- case "set:sys": return new ServiceSetSys();
- case "sfdnsres": return new ServiceSfdnsres();
- case "sm:": return new ServiceSm();
- case "ssl": return new ServiceSsl();
- case "time:s": return new ServiceTime();
- case "time:u": return new ServiceTime();
- case "vi:m": return new ServiceVi();
- case "vi:s": return new ServiceVi();
- case "vi:u": return new ServiceVi();
- }
-
- throw new NotImplementedException(Name);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
index a5f1b329..cb745e37 100644
--- a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
+++ b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
@@ -55,9 +55,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
return 0;
}
- HSession Session = new HSession(ServiceFactory.MakeService(Name));
+ HSession Session = new HSession(Context.Process.Services.GetService(Name));
- int Handle = Context.Ns.Os.Handles.GenerateId(Session);
+ int Handle = Context.Process.HandleTable.OpenHandle(Session);
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
diff --git a/Ryujinx.Core/OsHle/Display.cs b/Ryujinx.Core/OsHle/Services/Vi/Display.cs
index 590841fc..ceadc393 100644
--- a/Ryujinx.Core/OsHle/Display.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/Display.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Core.OsHle
+namespace Ryujinx.Core.OsHle.IpcServices.Vi
{
class Display
{
diff --git a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
index 4e40b99b..0ff1f909 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
@@ -15,6 +15,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+ private IdDictionary Displays;
+
public IApplicationDisplayService()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
@@ -28,14 +30,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ 2020, OpenLayer },
{ 2021, CloseLayer },
{ 2030, CreateStrayLayer },
+ { 2031, DestroyStrayLayer },
{ 2101, SetLayerScalingMode },
{ 5202, GetDisplayVSyncEvent }
};
+
+ Displays = new IdDictionary();
}
public long GetRelayService(ServiceCtx Context)
{
- MakeObject(Context, new IHOSBinderDriver());
+ MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer));
return 0;
}
@@ -56,7 +61,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
public long GetIndirectDisplayTransactionService(ServiceCtx Context)
{
- MakeObject(Context, new IHOSBinderDriver());
+ MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer));
return 0;
}
@@ -65,7 +70,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{
string Name = GetDisplayName(Context);
- long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name));
+ long DisplayId = Displays.Add(new Display(Name));
Context.ResponseData.Write(DisplayId);
@@ -76,7 +81,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{
int DisplayId = Context.RequestData.ReadInt32();
- Context.Ns.Os.Displays.Delete(DisplayId);
+ Displays.Delete(DisplayId);
return 0;
}
@@ -99,6 +104,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
public long CloseLayer(ServiceCtx Context)
{
+ long LayerId = Context.RequestData.ReadInt64();
+
return 0;
}
@@ -109,7 +116,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
- Display Disp = Context.Ns.Os.Displays.GetData<Display>((int)DisplayId);
+ Display Disp = Displays.GetData<Display>((int)DisplayId);
byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
@@ -121,6 +128,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
return 0;
}
+ public long DestroyStrayLayer(ServiceCtx Context)
+ {
+ return 0;
+ }
+
public long SetLayerScalingMode(ServiceCtx Context)
{
int ScalingMode = Context.RequestData.ReadInt32();
@@ -133,7 +145,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{
string Name = GetDisplayName(Context);
- int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+ int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
diff --git a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
index a89c1df8..b24a773b 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
@@ -1,6 +1,7 @@
using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.IpcServices.Android;
+using Ryujinx.Graphics.Gal;
using System;
using System.Collections.Generic;
@@ -14,7 +15,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
private NvFlinger Flinger;
- public IHOSBinderDriver()
+ public IHOSBinderDriver(IGalRenderer Renderer)
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
@@ -23,7 +24,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ 2, GetNativeHandle }
};
- Flinger = new NvFlinger();
+ Flinger = new NvFlinger(Renderer);
}
public long TransactParcel(ServiceCtx Context)
diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
index 1d394fb4..5309dcab 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
@@ -1,5 +1,6 @@
using ChocolArm64.Memory;
-using Ryujinx.Core.OsHle.Handles;
+using Ryujinx.Core.OsHle.IpcServices.NvServices;
+using Ryujinx.Graphics.Gal;
using System;
using System.IO;
using System.Collections.Generic;
@@ -54,18 +55,27 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
public GbpBuffer Data;
}
+ private IGalRenderer Renderer;
+
private BufferEntry[] BufferQueue;
private ManualResetEvent WaitBufferFree;
+
+ private object RenderQueueLock;
+
+ private int RenderQueueCount;
+
+ private bool NvFlingerDisposed;
private bool KeepRunning;
- public NvFlinger()
+ public NvFlinger(IGalRenderer Renderer)
{
Commands = new Dictionary<(string, int), ServiceProcessParcel>()
{
{ ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer },
{ ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer },
{ ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer },
{ ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer },
{ ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery },
@@ -74,10 +84,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
};
+ this.Renderer = Renderer;
+
BufferQueue = new BufferEntry[0x40];
WaitBufferFree = new ManualResetEvent(false);
+ RenderQueueLock = new object();
+
KeepRunning = true;
}
@@ -193,6 +207,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
}
+ private long GbpDetachBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ return MakeReplyParcel(Context, 0);
+ }
+
private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader)
{
//TODO: Errors.
@@ -266,7 +285,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
long FbSize = (uint)FbWidth * FbHeight * 4;
- HNvMap NvMap = GetNvMap(Context, Slot);
+ NvMap NvMap = GetNvMap(Context, Slot);
if ((ulong)(NvMap.Address + FbSize) > AMemoryMgr.AddrSize)
{
@@ -330,7 +349,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
Rotate = -MathF.PI * 0.5f;
}
- byte* Fb = (byte*)Context.Ns.Memory.Ram + NvMap.Address;
+ lock (RenderQueueLock)
+ {
+ if (NvFlingerDisposed)
+ {
+ return;
+ }
+
+ Interlocked.Increment(ref RenderQueueCount);
+ }
+
+ byte* Fb = (byte*)Context.Memory.Ram + NvMap.Address;
Context.Ns.Gpu.Renderer.QueueAction(delegate()
{
@@ -346,6 +375,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
BufferQueue[Slot].State = BufferState.Free;
+ Interlocked.Decrement(ref RenderQueueCount);
+
lock (WaitBufferFree)
{
WaitBufferFree.Set();
@@ -353,7 +384,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
});
}
- private HNvMap GetNvMap(ServiceCtx Context, int Slot)
+ private NvMap GetNvMap(ServiceCtx Context, int Slot)
{
int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
@@ -366,7 +397,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
NvMapHandle = BitConverter.ToInt32(RawValue, 0);
}
- return Context.Ns.Os.Handles.GetData<HNvMap>(NvMapHandle);
+ ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv");
+
+ return NvDrv.GetNvMap(NvMapHandle);
}
private int GetFreeSlotBlocking(int Width, int Height)
@@ -432,10 +465,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
Dispose(true);
}
- protected virtual void Dispose(bool disposing)
+ protected virtual void Dispose(bool Disposing)
{
- if (disposing)
+ if (Disposing && !NvFlingerDisposed)
{
+ lock (RenderQueueLock)
+ {
+ NvFlingerDisposed = true;
+ }
+
+ //Ensure that all pending actions was sent before
+ //we can safely assume that the class was disposed.
+ while (RenderQueueCount > 0)
+ {
+ Thread.Yield();
+ }
+
+ Renderer.ResetFrameBuffer();
+
lock (WaitBufferFree)
{
KeepRunning = false;
diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
index b3e6262d..3ce56a3c 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
@@ -1,12 +1,13 @@
using ChocolArm64.Events;
using ChocolArm64.Memory;
using ChocolArm64.State;
+using Ryujinx.Core.OsHle.Handles;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.Svc
{
- partial class SvcHandler
+ partial class SvcHandler : IDisposable
{
private delegate void SvcFunc(AThreadState ThreadState);
@@ -16,10 +17,12 @@ namespace Ryujinx.Core.OsHle.Svc
private Process Process;
private AMemory Memory;
- private static Random Rng;
-
+ private HashSet<(HSharedMem, long)> MappedSharedMems;
+
private ulong CurrentHeapSize;
+ private static Random Rng;
+
public SvcHandler(Switch Ns, Process Process)
{
SvcFuncs = new Dictionary<int, SvcFunc>()
@@ -32,6 +35,7 @@ namespace Ryujinx.Core.OsHle.Svc
{ 0x07, SvcExitProcess },
{ 0x08, SvcCreateThread },
{ 0x09, SvcStartThread },
+ { 0x0a, SvcExitThread },
{ 0x0b, SvcSleepThread },
{ 0x0c, SvcGetThreadPriority },
{ 0x0d, SvcSetThreadPriority },
@@ -60,6 +64,8 @@ namespace Ryujinx.Core.OsHle.Svc
this.Ns = Ns;
this.Process = Process;
this.Memory = Process.Memory;
+
+ MappedSharedMems = new HashSet<(HSharedMem, long)>();
}
static SvcHandler()
@@ -84,5 +90,26 @@ namespace Ryujinx.Core.OsHle.Svc
throw new NotImplementedException(e.Id.ToString("x4"));
}
}
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool Disposing)
+ {
+ if (Disposing)
+ {
+ lock (MappedSharedMems)
+ {
+ foreach ((HSharedMem SharedMem, long Position) in MappedSharedMems)
+ {
+ SharedMem.RemoveVirtualPosition(Memory, Position);
+ }
+
+ MappedSharedMems.Clear();
+ }
+ }
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
index c15f449b..80f24d2b 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
@@ -165,7 +165,7 @@ namespace Ryujinx.Core.OsHle.Svc
return;
}
- HSharedMem SharedMem = Ns.Os.Handles.GetData<HSharedMem>(Handle);
+ HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
if (SharedMem != null)
{
@@ -175,7 +175,12 @@ namespace Ryujinx.Core.OsHle.Svc
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
- SharedMem.AddVirtualPosition(Src);
+ lock (MappedSharedMems)
+ {
+ MappedSharedMems.Add((SharedMem, Src));
+ }
+
+ SharedMem.AddVirtualPosition(Memory, Src);
ThreadState.X0 = 0;
}
@@ -198,12 +203,19 @@ namespace Ryujinx.Core.OsHle.Svc
return;
}
- HSharedMem HndData = Ns.Os.Handles.GetData<HSharedMem>(Handle);
+ HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
- if (HndData != null)
+ if (SharedMem != null)
{
Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory);
+ SharedMem.RemoveVirtualPosition(Memory, Src);
+
+ lock (MappedSharedMems)
+ {
+ MappedSharedMems.Remove((SharedMem, Src));
+ }
+
ThreadState.X0 = 0;
}
@@ -229,12 +241,12 @@ namespace Ryujinx.Core.OsHle.Svc
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
- HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
-
- int Handle = Ns.Os.Handles.GenerateId(HndData);
+ HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
- ThreadState.X1 = (ulong)Handle;
+ ulong Handle = (ulong)Process.HandleTable.OpenHandle(TMem);
+
ThreadState.X0 = 0;
+ ThreadState.X1 = Handle;
}
private static bool IsValidPosition(long Position)
diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
index f7009035..671a32d3 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
@@ -3,7 +3,6 @@ using ChocolArm64.State;
using Ryujinx.Core.OsHle.Exceptions;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
-using Ryujinx.Core.OsHle.IpcServices;
using System;
using System.Threading;
@@ -35,7 +34,7 @@ namespace Ryujinx.Core.OsHle.Svc
{
int Handle = (int)ThreadState.X0;
- Ns.Os.CloseHandle(Handle);
+ Process.HandleTable.CloseHandle(Handle);
ThreadState.X0 = 0;
}
@@ -80,10 +79,12 @@ namespace Ryujinx.Core.OsHle.Svc
//TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise.
- HSession Session = new HSession(ServiceFactory.MakeService(Name));
+ HSession Session = new HSession(Process.Services.GetService(Name));
- ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session);
+ ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
+
ThreadState.X0 = 0;
+ ThreadState.X1 = Handle;
}
private void SvcSendSyncRequest(AThreadState ThreadState)
@@ -119,13 +120,21 @@ namespace Ryujinx.Core.OsHle.Svc
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
- HSession Session = Ns.Os.Handles.GetData<HSession>(Handle);
+ HSession Session = Process.HandleTable.GetData<HSession>(Handle);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
if (Session != null)
{
- IpcHandler.IpcCall(Ns, Memory, Session, Cmd, ThreadState.ThreadId, CmdPtr, Handle);
+ IpcHandler.IpcCall(
+ Ns,
+ Process,
+ Memory,
+ Session,
+ Cmd,
+ ThreadState.ThreadId,
+ CmdPtr,
+ Handle);
byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs
index 6afd2e61..231ee2a2 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcThread.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs
@@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc
{
int Handle = (int)ThreadState.X0;
- HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+ HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
if (Thread != null)
{
@@ -51,6 +51,13 @@ namespace Ryujinx.Core.OsHle.Svc
//TODO: Error codes.
}
+ private void SvcExitThread(AThreadState ThreadState)
+ {
+ HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
+ CurrThread.Thread.StopExecution();
+ }
+
private void SvcSleepThread(AThreadState ThreadState)
{
ulong NanoSecs = ThreadState.X0;
@@ -71,7 +78,7 @@ namespace Ryujinx.Core.OsHle.Svc
{
int Handle = (int)ThreadState.X1;
- HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+ HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
if (Thread != null)
{
@@ -87,7 +94,7 @@ namespace Ryujinx.Core.OsHle.Svc
int Handle = (int)ThreadState.X1;
int Prio = (int)ThreadState.X0;
- HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+ HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
if (Thread != null)
{
@@ -110,7 +117,7 @@ namespace Ryujinx.Core.OsHle.Svc
{
int Handle = (int)ThreadState.X0;
- HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+ HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
if (Thread != null)
{
diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
index 6e488da5..38356073 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
@@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc
long MutexAddress = (long)ThreadState.X1;
int RequestingThreadHandle = (int)ThreadState.X2;
- HThread RequestingThread = Ns.Os.Handles.GetData<HThread>(RequestingThreadHandle);
+ HThread RequestingThread = Process.HandleTable.GetData<HThread>(RequestingThreadHandle);
Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
@@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc
int ThreadHandle = (int)ThreadState.X2;
long Timeout = (long)ThreadState.X3;
- HThread Thread = Ns.Os.Handles.GetData<HThread>(ThreadHandle);
+ HThread Thread = Process.HandleTable.GetData<HThread>(ThreadHandle);
Mutex M = new Mutex(Process, MutexAddress, ThreadHandle);
diff --git a/Ryujinx.Core/OsHle/Utilities/IdPool.cs b/Ryujinx.Core/OsHle/Utilities/IdPool.cs
deleted file mode 100644
index a7e181fa..00000000
--- a/Ryujinx.Core/OsHle/Utilities/IdPool.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System.Collections.Generic;
-
-namespace Ryujinx.Core.OsHle.Utilities
-{
- class IdPool
- {
- private HashSet<int> Ids;
-
- private int CurrId;
- private int MinId;
- private int MaxId;
-
- public IdPool(int Min, int Max)
- {
- Ids = new HashSet<int>();
-
- CurrId = Min;
- MinId = Min;
- MaxId = Max;
- }
-
- public IdPool() : this(1, int.MaxValue) { }
-
- public int GenerateId()
- {
- lock (Ids)
- {
- for (int Cnt = MinId; Cnt < MaxId; Cnt++)
- {
- if (Ids.Add(CurrId))
- {
- return CurrId;
- }
-
- if (CurrId++ == MaxId)
- {
- CurrId = MinId;
- }
- }
-
- return -1;
- }
- }
-
- public bool DeleteId(int Id)
- {
- lock (Ids)
- {
- return Ids.Remove(Id);
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs
index f7ce109f..487f3bdb 100644
--- a/Ryujinx.Core/Switch.cs
+++ b/Ryujinx.Core/Switch.cs
@@ -1,4 +1,3 @@
-using ChocolArm64.Memory;
using Ryujinx.Core.Input;
using Ryujinx.Core.OsHle;
using Ryujinx.Core.Settings;
@@ -10,8 +9,6 @@ namespace Ryujinx.Core
{
public class Switch : IDisposable
{
- internal AMemory Memory { get; private set; }
-
internal NsGpu Gpu { get; private set; }
internal Horizon Os { get; private set; }
internal VirtualFs VFs { get; private set; }
@@ -24,13 +21,11 @@ namespace Ryujinx.Core
public Switch(IGalRenderer Renderer)
{
- Memory = new AMemory();
-
Gpu = new NsGpu(Renderer);
VFs = new VirtualFs();
- Hid = new Hid(Memory);
+ Hid = new Hid();
Statistics = new PerformanceStatistics();
@@ -42,11 +37,6 @@ namespace Ryujinx.Core
Settings = new SetSys();
}
- public void FinalizeAllProcesses()
- {
- Os.FinalizeAllProcesses();
- }
-
public void LoadCart(string ExeFsDir, string RomFsFile = null)
{
Os.LoadCart(ExeFsDir, RomFsFile);
@@ -67,12 +57,11 @@ namespace Ryujinx.Core
Dispose(true);
}
- protected virtual void Dispose(bool disposing)
+ protected virtual void Dispose(bool Disposing)
{
- if (disposing)
+ if (Disposing)
{
- Memory.Dispose();
-
+ Os.Dispose();
VFs.Dispose();
}
}
diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs
index 83d2c699..aa4eac4e 100644
--- a/Ryujinx.Graphics/Gal/IGalRenderer.cs
+++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal
void RunActions();
void InitializeFrameBuffer();
+ void ResetFrameBuffer();
void Render();
void SetWindowSize(int Width, int Height);
void SetFrameBuffer(
diff --git a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
index 7dc4bffe..b761811f 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
@@ -24,6 +24,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private byte* FbPtr;
+ private object FbPtrLock;
+
public FrameBuffer(int Width, int Height)
{
if (Width < 0)
@@ -36,6 +38,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
throw new ArgumentOutOfRangeException(nameof(Height));
}
+ FbPtrLock = new object();
+
TexWidth = Width;
TexHeight = Height;
@@ -152,7 +156,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
throw new ArgumentOutOfRangeException(nameof(Height));
}
- FbPtr = Fb;
+ lock (FbPtrLock)
+ {
+ FbPtr = Fb;
+ }
if (Width != TexWidth ||
Height != TexHeight)
@@ -178,17 +185,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.Uniform2(OffsetUniformLocation, Offs);
}
- public void Render()
+ public void Reset()
{
- if (FbPtr == null)
+ lock (FbPtrLock)
{
- return;
+ FbPtr = null;
}
+ }
- for (int Y = 0; Y < TexHeight; Y++)
- for (int X = 0; X < TexWidth; X++)
+ public void Render()
+ {
+ lock (FbPtrLock)
{
- Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
+ if (FbPtr == null)
+ {
+ return;
+ }
+
+ for (int Y = 0; Y < TexHeight; Y++)
+ for (int X = 0; X < TexWidth; X++)
+ {
+ Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
+ }
}
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
index bdedfc1a..002e54da 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
@@ -43,6 +43,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
FbRenderer = new FrameBuffer(1280, 720);
}
+ public void ResetFrameBuffer()
+ {
+ FbRenderer.Reset();
+ }
+
public void QueueAction(Action ActionMthd)
{
ActionsQueue.Enqueue(ActionMthd);
diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs
index 0b35a7a6..b5bbdbc1 100644
--- a/Ryujinx.Tests/Cpu/CpuTest.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest.cs
@@ -28,7 +28,7 @@ namespace Ryujinx.Tests.Cpu
ATranslator Translator = new ATranslator();
Memory = new AMemory();
Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
- Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint);
+ Thread = new AThread(Translator, Memory, EntryPoint);
}
[TearDown]