Allow more than one process, free resources on process dispose, implement SvcExitThread
This commit is contained in:
parent
3aaa4717b6
commit
7a27990faa
46 changed files with 926 additions and 598 deletions
|
@ -14,43 +14,30 @@ namespace ChocolArm64
|
||||||
|
|
||||||
private ATranslator Translator;
|
private ATranslator Translator;
|
||||||
|
|
||||||
private ThreadPriority Priority;
|
|
||||||
|
|
||||||
private Thread Work;
|
private Thread Work;
|
||||||
|
|
||||||
public event EventHandler WorkFinished;
|
public event EventHandler WorkFinished;
|
||||||
|
|
||||||
public int ThreadId => ThreadState.ThreadId;
|
public int ThreadId => ThreadState.ThreadId;
|
||||||
|
|
||||||
public bool IsAlive => Work.IsAlive;
|
private int IsExecuting;
|
||||||
|
|
||||||
private bool IsExecuting;
|
public AThread(ATranslator Translator, AMemory Memory, long EntryPoint)
|
||||||
|
|
||||||
private object ExecuteLock;
|
|
||||||
|
|
||||||
public AThread(ATranslator Translator, AMemory Memory, ThreadPriority Priority, long EntryPoint)
|
|
||||||
{
|
{
|
||||||
this.Translator = Translator;
|
this.Translator = Translator;
|
||||||
this.Memory = Memory;
|
this.Memory = Memory;
|
||||||
this.Priority = Priority;
|
|
||||||
this.EntryPoint = EntryPoint;
|
this.EntryPoint = EntryPoint;
|
||||||
|
|
||||||
ThreadState = new AThreadState();
|
ThreadState = new AThreadState();
|
||||||
ExecuteLock = new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopExecution() => Translator.StopExecution();
|
ThreadState.Running = true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Execute()
|
public bool Execute()
|
||||||
{
|
{
|
||||||
lock (ExecuteLock)
|
if (Interlocked.Exchange(ref IsExecuting, 1) == 1)
|
||||||
{
|
{
|
||||||
if (IsExecuting)
|
return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsExecuting = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Work = new Thread(delegate()
|
Work = new Thread(delegate()
|
||||||
|
@ -62,11 +49,11 @@ namespace ChocolArm64
|
||||||
WorkFinished?.Invoke(this, EventArgs.Empty);
|
WorkFinished?.Invoke(this, EventArgs.Empty);
|
||||||
});
|
});
|
||||||
|
|
||||||
Work.Priority = Priority;
|
|
||||||
|
|
||||||
Work.Start();
|
Work.Start();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StopExecution() => ThreadState.Running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,8 +22,6 @@ namespace ChocolArm64
|
||||||
|
|
||||||
public bool EnableCpuTrace { get; set; }
|
public bool EnableCpuTrace { get; set; }
|
||||||
|
|
||||||
private bool KeepRunning;
|
|
||||||
|
|
||||||
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||||
{
|
{
|
||||||
SubBlocks = new HashSet<long>();
|
SubBlocks = new HashSet<long>();
|
||||||
|
@ -38,12 +36,8 @@ namespace ChocolArm64
|
||||||
{
|
{
|
||||||
this.SymbolTable = new ConcurrentDictionary<long, string>();
|
this.SymbolTable = new ConcurrentDictionary<long, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
KeepRunning = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void StopExecution() => KeepRunning = false;
|
|
||||||
|
|
||||||
internal void ExecuteSubroutine(AThread Thread, long Position)
|
internal void ExecuteSubroutine(AThread Thread, long Position)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
|
@ -70,7 +64,7 @@ namespace ChocolArm64
|
||||||
|
|
||||||
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
|
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)
|
internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
|
||||||
|
|
|
@ -34,6 +34,22 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitCall(MthdInfo);
|
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)
|
if (Context.CurrBlock.Next != null)
|
||||||
{
|
{
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||||
|
|
|
@ -29,6 +29,8 @@ namespace ChocolArm64.State
|
||||||
public int ProcessId;
|
public int ProcessId;
|
||||||
public int ThreadId;
|
public int ThreadId;
|
||||||
|
|
||||||
|
public bool Running { get; set; }
|
||||||
|
|
||||||
public long TpidrEl0 { get; set; }
|
public long TpidrEl0 { get; set; }
|
||||||
public long Tpidr { get; set; }
|
public long Tpidr { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -63,17 +63,13 @@ namespace Ryujinx.Core.Input
|
||||||
|
|
||||||
private object ShMemLock;
|
private object ShMemLock;
|
||||||
|
|
||||||
private long[] ShMemPositions;
|
private (AMemory, long)[] ShMemPositions;
|
||||||
|
|
||||||
private AMemory Memory;
|
public Hid()
|
||||||
|
|
||||||
public Hid(AMemory Memory)
|
|
||||||
{
|
{
|
||||||
this.Memory = Memory;
|
|
||||||
|
|
||||||
ShMemLock = new object();
|
ShMemLock = new object();
|
||||||
|
|
||||||
ShMemPositions = new long[0];
|
ShMemPositions = new (AMemory, long)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ShMemMap(object sender, EventArgs e)
|
internal void ShMemMap(object sender, EventArgs e)
|
||||||
|
@ -84,11 +80,11 @@ namespace Ryujinx.Core.Input
|
||||||
{
|
{
|
||||||
ShMemPositions = SharedMem.GetVirtualPositions();
|
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(
|
InitializeJoyconPair(
|
||||||
BasePosition,
|
Memory,
|
||||||
|
Position,
|
||||||
JoyConColor.Body_Neon_Red,
|
JoyConColor.Body_Neon_Red,
|
||||||
JoyConColor.Buttons_Neon_Red,
|
JoyConColor.Buttons_Neon_Red,
|
||||||
JoyConColor.Body_Neon_Blue,
|
JoyConColor.Body_Neon_Blue,
|
||||||
|
@ -113,13 +110,14 @@ namespace Ryujinx.Core.Input
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeJoyconPair(
|
private void InitializeJoyconPair(
|
||||||
long BasePosition,
|
AMemory Memory,
|
||||||
|
long Position,
|
||||||
JoyConColor LeftColorBody,
|
JoyConColor LeftColorBody,
|
||||||
JoyConColor LeftColorButtons,
|
JoyConColor LeftColorButtons,
|
||||||
JoyConColor RightColorBody,
|
JoyConColor RightColorBody,
|
||||||
JoyConColor RightColorButtons)
|
JoyConColor RightColorButtons)
|
||||||
{
|
{
|
||||||
long BaseControllerOffset = BasePosition + HidControllersOffset + 8 * HidControllerSize;
|
long BaseControllerOffset = Position + HidControllersOffset + 8 * HidControllerSize;
|
||||||
|
|
||||||
HidControllerType Type =
|
HidControllerType Type =
|
||||||
HidControllerType.ControllerType_Handheld |
|
HidControllerType.ControllerType_Handheld |
|
||||||
|
@ -160,7 +158,7 @@ namespace Ryujinx.Core.Input
|
||||||
{
|
{
|
||||||
lock (ShMemLock)
|
lock (ShMemLock)
|
||||||
{
|
{
|
||||||
foreach (long Position in ShMemPositions)
|
foreach ((AMemory Memory, long Position) in ShMemPositions)
|
||||||
{
|
{
|
||||||
long ControllerOffset = Position + HidControllersOffset;
|
long ControllerOffset = Position + HidControllersOffset;
|
||||||
|
|
||||||
|
@ -207,7 +205,7 @@ namespace Ryujinx.Core.Input
|
||||||
{
|
{
|
||||||
lock (ShMemLock)
|
lock (ShMemLock)
|
||||||
{
|
{
|
||||||
foreach (long Position in ShMemPositions)
|
foreach ((AMemory Memory, long Position) in ShMemPositions)
|
||||||
{
|
{
|
||||||
long TouchScreenOffset = Position + HidTouchScreenOffset;
|
long TouchScreenOffset = Position + HidTouchScreenOffset;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ namespace Ryujinx.Core
|
||||||
{
|
{
|
||||||
public static class Logging
|
public static class Logging
|
||||||
{
|
{
|
||||||
private static Stopwatch ExecutionTime = new Stopwatch();
|
private static Stopwatch ExecutionTime;
|
||||||
|
|
||||||
private const string LogFileName = "Ryujinx.log";
|
private const string LogFileName = "Ryujinx.log";
|
||||||
|
|
||||||
private static bool EnableInfo = Config.LoggingEnableInfo;
|
private static bool EnableInfo = Config.LoggingEnableInfo;
|
||||||
|
@ -23,6 +24,10 @@ namespace Ryujinx.Core
|
||||||
static Logging()
|
static Logging()
|
||||||
{
|
{
|
||||||
if (File.Exists(LogFileName)) File.Delete(LogFileName);
|
if (File.Exists(LogFileName)) File.Delete(LogFileName);
|
||||||
|
|
||||||
|
ExecutionTime = new Stopwatch();
|
||||||
|
|
||||||
|
ExecutionTime.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetExecutionTime()
|
public static string GetExecutionTime()
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
public class CondVar
|
class CondVar
|
||||||
{
|
{
|
||||||
private Process Process;
|
private Process Process;
|
||||||
|
|
||||||
|
|
|
@ -1,58 +1,48 @@
|
||||||
using Ryujinx.Core.OsHle.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle.Handles
|
namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
class HDomain : HSession
|
class HDomain : HSession, IDisposable
|
||||||
{
|
{
|
||||||
private Dictionary<int, object> Objects;
|
private IdDictionary Objects;
|
||||||
|
|
||||||
private IdPool ObjIds;
|
|
||||||
|
|
||||||
public HDomain(HSession Session) : base(Session)
|
public HDomain(HSession Session) : base(Session)
|
||||||
{
|
{
|
||||||
Objects = new Dictionary<int, object>();
|
Objects = new IdDictionary();
|
||||||
|
|
||||||
ObjIds = new IdPool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GenerateObjectId(object Obj)
|
public int Add(object Obj)
|
||||||
{
|
{
|
||||||
int Id = ObjIds.GenerateId();
|
return Objects.Add(Obj);
|
||||||
|
|
||||||
if (Id == -1)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Objects.Add(Id, Obj);
|
|
||||||
|
|
||||||
return Id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteObject(int Id)
|
public bool Delete(int Id)
|
||||||
{
|
{
|
||||||
if (Objects.TryGetValue(Id, out object Obj))
|
return Objects.Delete(Id);
|
||||||
{
|
|
||||||
if (Obj is IDisposable DisposableObj)
|
|
||||||
{
|
|
||||||
DisposableObj.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjIds.DeleteId(Id);
|
|
||||||
Objects.Remove(Id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object GetObject(int Id)
|
public object GetObject(int Id)
|
||||||
{
|
{
|
||||||
if (Objects.TryGetValue(Id, out object Obj))
|
return Objects.GetData(Id);
|
||||||
{
|
}
|
||||||
return Obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
if (Disposing)
|
||||||
|
{
|
||||||
|
foreach (object Obj in Objects)
|
||||||
|
{
|
||||||
|
if (Obj is IDisposable DisposableObj)
|
||||||
|
{
|
||||||
|
DisposableObj.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using ChocolArm64.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -5,37 +6,37 @@ namespace Ryujinx.Core.OsHle.Handles
|
||||||
{
|
{
|
||||||
class HSharedMem
|
class HSharedMem
|
||||||
{
|
{
|
||||||
private List<long> Positions;
|
private List<(AMemory, long)> Positions;
|
||||||
|
|
||||||
public EventHandler<EventArgs> MemoryMapped;
|
public EventHandler<EventArgs> MemoryMapped;
|
||||||
public EventHandler<EventArgs> MemoryUnmapped;
|
public EventHandler<EventArgs> MemoryUnmapped;
|
||||||
|
|
||||||
public HSharedMem()
|
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)
|
lock (Positions)
|
||||||
{
|
{
|
||||||
Positions.Add(Position);
|
Positions.Add((Memory, Position));
|
||||||
|
|
||||||
MemoryMapped?.Invoke(this, EventArgs.Empty);
|
MemoryMapped?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveVirtualPosition(long Position)
|
public void RemoveVirtualPosition(AMemory Memory, long Position)
|
||||||
{
|
{
|
||||||
lock (Positions)
|
lock (Positions)
|
||||||
{
|
{
|
||||||
Positions.Remove(Position);
|
Positions.Remove((Memory, Position));
|
||||||
|
|
||||||
MemoryUnmapped?.Invoke(this, EventArgs.Empty);
|
MemoryUnmapped?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long[] GetVirtualPositions()
|
public (AMemory, long)[] GetVirtualPositions()
|
||||||
{
|
{
|
||||||
return Positions.ToArray();
|
return Positions.ToArray();
|
||||||
}
|
}
|
||||||
|
|
63
Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
Normal file
63
Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,5 +37,33 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
Position += 0x18;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,23 @@
|
||||||
using Ryujinx.Core.Loaders.Executables;
|
using Ryujinx.Core.Loaders.Executables;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using Ryujinx.Core.OsHle.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
public class Horizon
|
public class Horizon : IDisposable
|
||||||
{
|
{
|
||||||
internal const int HidSize = 0x40000;
|
internal const int HidSize = 0x40000;
|
||||||
internal const int FontSize = 0x50;
|
internal const int FontSize = 0x50;
|
||||||
|
|
||||||
internal int HidHandle { get; private set; }
|
internal ConcurrentDictionary<long, Mutex> Mutexes { get; private set; }
|
||||||
internal int FontHandle { get; private set; }
|
internal ConcurrentDictionary<long, CondVar> CondVars { 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; }
|
|
||||||
|
|
||||||
private ConcurrentDictionary<int, Process> Processes;
|
private ConcurrentDictionary<int, Process> Processes;
|
||||||
|
|
||||||
internal HSharedMem HidSharedMem;
|
internal HSharedMem HidSharedMem;
|
||||||
|
internal HSharedMem FontSharedMem;
|
||||||
|
|
||||||
private Switch Ns;
|
private Switch Ns;
|
||||||
|
|
||||||
|
@ -35,25 +25,13 @@ namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
this.Ns = Ns;
|
this.Ns = Ns;
|
||||||
|
|
||||||
IdGen = new IdPool();
|
|
||||||
NvMapIds = new IdPool();
|
|
||||||
|
|
||||||
Handles = new IdPoolWithObj();
|
|
||||||
Fds = new IdPoolWithObj();
|
|
||||||
Displays = new IdPoolWithObj();
|
|
||||||
|
|
||||||
Mutexes = new ConcurrentDictionary<long, Mutex>();
|
Mutexes = new ConcurrentDictionary<long, Mutex>();
|
||||||
CondVars = new ConcurrentDictionary<long, CondVar>();
|
CondVars = new ConcurrentDictionary<long, CondVar>();
|
||||||
|
|
||||||
Processes = new ConcurrentDictionary<int, Process>();
|
Processes = new ConcurrentDictionary<int, Process>();
|
||||||
|
|
||||||
HidSharedMem = new HSharedMem();
|
HidSharedMem = new HSharedMem();
|
||||||
|
FontSharedMem = new HSharedMem();
|
||||||
HidHandle = Handles.GenerateId(HidSharedMem);
|
|
||||||
|
|
||||||
FontHandle = Handles.GenerateId(new HSharedMem());
|
|
||||||
|
|
||||||
HidSharedMem.AddVirtualPosition(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
||||||
|
@ -63,9 +41,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
Ns.VFs.LoadRomFs(RomFsFile);
|
Ns.VFs.LoadRomFs(RomFsFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ProcessId = IdGen.GenerateId();
|
Process MainProcess = MakeProcess();
|
||||||
|
|
||||||
Process MainProcess = new Process(Ns, ProcessId);
|
|
||||||
|
|
||||||
void LoadNso(string FileName)
|
void LoadNso(string FileName)
|
||||||
{
|
{
|
||||||
|
@ -96,17 +72,13 @@ namespace Ryujinx.Core.OsHle
|
||||||
LoadNso("sdk");
|
LoadNso("sdk");
|
||||||
|
|
||||||
MainProcess.Run();
|
MainProcess.Run();
|
||||||
|
|
||||||
Processes.TryAdd(ProcessId, MainProcess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadProgram(string FileName)
|
public void LoadProgram(string FileName)
|
||||||
{
|
{
|
||||||
bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
|
bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
|
||||||
|
|
||||||
int ProcessId = IdGen.GenerateId();
|
Process MainProcess = MakeProcess();
|
||||||
|
|
||||||
Process MainProcess = new Process(Ns, ProcessId);
|
|
||||||
|
|
||||||
using (FileStream Input = new FileStream(FileName, FileMode.Open))
|
using (FileStream Input = new FileStream(FileName, FileMode.Open))
|
||||||
{
|
{
|
||||||
|
@ -117,34 +89,67 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
MainProcess.SetEmptyArgs();
|
MainProcess.SetEmptyArgs();
|
||||||
MainProcess.Run(IsNro);
|
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();
|
int ProcessId = 0;
|
||||||
|
|
||||||
|
while (Processes.ContainsKey(ProcessId))
|
||||||
|
{
|
||||||
|
ProcessId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process = new Process(Ns, ProcessId);
|
||||||
|
|
||||||
|
Processes.TryAdd(ProcessId, Process);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Process;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ExitProcess(int ProcessId)
|
||||||
|
{
|
||||||
|
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
|
||||||
|
{
|
||||||
|
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.TryRemove(ProcessId, out Process))
|
||||||
|
{
|
||||||
|
Process.StopAllThreadsAsync();
|
||||||
Process.Dispose();
|
Process.Dispose();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool ExitProcess(int ProcessId)
|
if (Processes.Count == 0)
|
||||||
{
|
{
|
||||||
bool Success = Processes.TryRemove(ProcessId, out Process Process);
|
Ns.OnFinish(EventArgs.Empty);
|
||||||
|
}
|
||||||
if (Success)
|
|
||||||
{
|
|
||||||
Process.StopAllThreads();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Processes.Count == 0)
|
|
||||||
{
|
|
||||||
Ns.OnFinish(EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool TryGetProcess(int ProcessId, out Process Process)
|
internal bool TryGetProcess(int ProcessId, out Process Process)
|
||||||
|
@ -152,19 +157,21 @@ namespace Ryujinx.Core.OsHle
|
||||||
return Processes.TryGetValue(ProcessId, out Process);
|
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(
|
foreach (Process Process in Processes.Values)
|
||||||
TransferMem.Position,
|
{
|
||||||
TransferMem.Size,
|
Process.StopAllThreadsAsync();
|
||||||
TransferMem.Perm);
|
Process.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handles.Delete(Handle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,31 +3,40 @@ using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
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;
|
private ConcurrentDictionary<int, object> Objs;
|
||||||
|
|
||||||
public IdPoolWithObj()
|
private int FreeIdHint = 1;
|
||||||
{
|
|
||||||
Ids = new IdPool();
|
|
||||||
|
|
||||||
|
public IdDictionary()
|
||||||
|
{
|
||||||
Objs = new ConcurrentDictionary<int, object>();
|
Objs = new ConcurrentDictionary<int, object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GenerateId(object Data)
|
public int Add(object Data)
|
||||||
{
|
{
|
||||||
int Id = Ids.GenerateId();
|
if (Objs.TryAdd(FreeIdHint, Data))
|
||||||
|
|
||||||
if (Id == -1 || !Objs.TryAdd(Id, Data))
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
return FreeIdHint++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Id;
|
return AddSlow(Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int AddSlow(object Data)
|
||||||
|
{
|
||||||
|
for (int Id = 1; Id < int.MaxValue; Id++)
|
||||||
|
{
|
||||||
|
if (Objs.TryAdd(Id, Data))
|
||||||
|
{
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ReplaceData(int Id, object Data)
|
public bool ReplaceData(int Id, object Data)
|
||||||
|
@ -42,6 +51,16 @@ namespace Ryujinx.Core.OsHle.Utilities
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object GetData(int Id)
|
||||||
|
{
|
||||||
|
if (Objs.TryGetValue(Id, out object Data))
|
||||||
|
{
|
||||||
|
return Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public T GetData<T>(int Id)
|
public T GetData<T>(int Id)
|
||||||
{
|
{
|
||||||
if (Objs.TryGetValue(Id, out object Data) && Data is T)
|
if (Objs.TryGetValue(Id, out object Data) && Data is T)
|
||||||
|
@ -52,7 +71,7 @@ namespace Ryujinx.Core.OsHle.Utilities
|
||||||
return default(T);
|
return default(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete(int Id)
|
public bool Delete(int Id)
|
||||||
{
|
{
|
||||||
if (Objs.TryRemove(Id, out object Obj))
|
if (Objs.TryRemove(Id, out object Obj))
|
||||||
{
|
{
|
||||||
|
@ -61,18 +80,22 @@ namespace Ryujinx.Core.OsHle.Utilities
|
||||||
DisposableObj.Dispose();
|
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()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
{
|
{
|
||||||
return Objs.GetEnumerator();
|
return Objs.Values.GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
||||||
|
|
||||||
public static void IpcCall(
|
public static void IpcCall(
|
||||||
Switch Ns,
|
Switch Ns,
|
||||||
|
Process Process,
|
||||||
AMemory Memory,
|
AMemory Memory,
|
||||||
HSession Session,
|
HSession Session,
|
||||||
IpcMessage Request,
|
IpcMessage Request,
|
||||||
|
@ -60,7 +61,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
||||||
}
|
}
|
||||||
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
|
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
|
||||||
{
|
{
|
||||||
Dom.DeleteObject(Request.DomObjId);
|
Dom.Delete(Request.DomObjId);
|
||||||
|
|
||||||
Response = FillResponse(Response, 0);
|
Response = FillResponse(Response, 0);
|
||||||
|
|
||||||
|
@ -100,6 +101,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
||||||
|
|
||||||
ServiceCtx Context = new ServiceCtx(
|
ServiceCtx Context = new ServiceCtx(
|
||||||
Ns,
|
Ns,
|
||||||
|
Process,
|
||||||
Memory,
|
Memory,
|
||||||
Session,
|
Session,
|
||||||
Request,
|
Request,
|
||||||
|
@ -124,15 +126,43 @@ namespace Ryujinx.Core.OsHle.Ipc
|
||||||
|
|
||||||
switch (CmdId)
|
switch (CmdId)
|
||||||
{
|
{
|
||||||
case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break;
|
case 0:
|
||||||
case 3: Request = IpcQueryBufferPointerSize(Response); break;
|
{
|
||||||
case 2: //IpcDuplicateSession, differences is unknown.
|
HDomain Dom = new HDomain(Session);
|
||||||
case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break;
|
|
||||||
|
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());
|
default: throw new NotImplementedException(CmdId.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Request.Type == IpcMessageType.Unknown2)
|
else if (Request.Type == IpcMessageType.CloseSession)
|
||||||
{
|
{
|
||||||
//TODO
|
//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)
|
private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
|
||||||
{
|
{
|
||||||
using (MemoryStream MS = new MemoryStream())
|
using (MemoryStream MS = new MemoryStream())
|
||||||
|
|
|
@ -2,9 +2,9 @@ namespace Ryujinx.Core.OsHle.Ipc
|
||||||
{
|
{
|
||||||
enum IpcMessageType
|
enum IpcMessageType
|
||||||
{
|
{
|
||||||
Response = 0,
|
Response = 0,
|
||||||
Unknown2 = 2,
|
CloseSession = 2,
|
||||||
Request = 4,
|
Request = 4,
|
||||||
Control = 5
|
Control = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
public class Mutex
|
class Mutex
|
||||||
{
|
{
|
||||||
private const int MutexHasListenersMask = 0x40000000;
|
private const int MutexHasListenersMask = 0x40000000;
|
||||||
|
|
||||||
|
|
|
@ -9,25 +9,32 @@ using Ryujinx.Core.OsHle.Svc;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle
|
||||||
{
|
{
|
||||||
public class Process : IDisposable
|
class Process : IDisposable
|
||||||
{
|
{
|
||||||
private const int TlsSize = 0x200;
|
private const int TlsSize = 0x200;
|
||||||
private const int TotalTlsSlots = 32;
|
private const int TotalTlsSlots = 32;
|
||||||
|
|
||||||
private Switch Ns;
|
private Switch Ns;
|
||||||
|
|
||||||
|
public bool NeedsHbAbi { get; private set; }
|
||||||
|
|
||||||
|
public long HbAbiDataPosition { get; private set; }
|
||||||
|
|
||||||
public int ProcessId { get; private set; }
|
public int ProcessId { get; private set; }
|
||||||
|
|
||||||
private ATranslator Translator;
|
private ATranslator Translator;
|
||||||
|
|
||||||
public AMemory Memory { get; private set; }
|
public AMemory Memory { get; private set; }
|
||||||
|
|
||||||
|
public ServiceMgr Services { get; private set; }
|
||||||
|
|
||||||
public KProcessScheduler Scheduler { get; private set; }
|
public KProcessScheduler Scheduler { get; private set; }
|
||||||
|
|
||||||
|
public KProcessHandleTable HandleTable { get; private set; }
|
||||||
|
|
||||||
private SvcHandler SvcHandler;
|
private SvcHandler SvcHandler;
|
||||||
|
|
||||||
private ConcurrentDictionary<int, AThread> TlsSlots;
|
private ConcurrentDictionary<int, AThread> TlsSlots;
|
||||||
|
@ -40,14 +47,22 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private long ImageBase;
|
private long ImageBase;
|
||||||
|
|
||||||
|
private bool ShouldDispose;
|
||||||
|
|
||||||
|
private bool Disposed;
|
||||||
|
|
||||||
public Process(Switch Ns, int ProcessId)
|
public Process(Switch Ns, int ProcessId)
|
||||||
{
|
{
|
||||||
this.Ns = Ns;
|
this.Ns = Ns;
|
||||||
this.ProcessId = ProcessId;
|
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);
|
SvcHandler = new SvcHandler(Ns, this);
|
||||||
|
|
||||||
|
@ -67,6 +82,11 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
public void LoadProgram(IExecutable Program)
|
public void LoadProgram(IExecutable Program)
|
||||||
{
|
{
|
||||||
|
if (Disposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(Process));
|
||||||
|
}
|
||||||
|
|
||||||
Logging.Info($"Image base at 0x{ImageBase:x16}.");
|
Logging.Info($"Image base at 0x{ImageBase:x16}.");
|
||||||
|
|
||||||
Executable Executable = new Executable(Program, Memory, ImageBase);
|
Executable Executable = new Executable(Program, Memory, ImageBase);
|
||||||
|
@ -78,11 +98,19 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
public void SetEmptyArgs()
|
public void SetEmptyArgs()
|
||||||
{
|
{
|
||||||
|
//TODO: This should be part of Run.
|
||||||
ImageBase += AMemoryMgr.PageSize;
|
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)
|
if (Executables.Count == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -102,11 +130,11 @@ namespace Ryujinx.Core.OsHle
|
||||||
return false;
|
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);
|
Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle);
|
||||||
|
|
||||||
|
@ -124,22 +152,21 @@ namespace Ryujinx.Core.OsHle
|
||||||
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
|
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)
|
if (MainThread != null)
|
||||||
{
|
{
|
||||||
while (MainThread.Thread.IsAlive)
|
MainThread.Thread.StopExecution();
|
||||||
{
|
|
||||||
MainThread.Thread.StopExecution();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (AThread Thread in TlsSlots.Values)
|
foreach (AThread Thread in TlsSlots.Values)
|
||||||
{
|
{
|
||||||
while (Thread.IsAlive)
|
Thread.StopExecution();
|
||||||
{
|
|
||||||
Thread.StopExecution();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,49 +177,26 @@ namespace Ryujinx.Core.OsHle
|
||||||
int Priority,
|
int Priority,
|
||||||
int ProcessorId)
|
int ProcessorId)
|
||||||
{
|
{
|
||||||
ThreadPriority ThreadPrio;
|
if (Disposed)
|
||||||
|
|
||||||
if (Priority < 12)
|
|
||||||
{
|
{
|
||||||
ThreadPrio = ThreadPriority.Highest;
|
throw new ObjectDisposedException(nameof(Process));
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AThread Thread = new AThread(GetTranslator(), Memory, ThreadPrio, EntryPoint);
|
AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
|
||||||
|
|
||||||
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
|
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
|
||||||
|
|
||||||
int Handle = Ns.Os.Handles.GenerateId(ThreadHnd);
|
int Handle = HandleTable.OpenHandle(ThreadHnd);
|
||||||
|
|
||||||
int TlsSlot = GetFreeTlsSlot(Thread);
|
int ThreadId = GetFreeTlsSlot(Thread);
|
||||||
|
|
||||||
if (TlsSlot == -1 || Handle == -1)
|
long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * TlsSize;
|
|
||||||
|
|
||||||
Thread.ThreadState.Break += BreakHandler;
|
Thread.ThreadState.Break += BreakHandler;
|
||||||
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
|
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
|
||||||
Thread.ThreadState.Undefined += UndefinedHandler;
|
Thread.ThreadState.Undefined += UndefinedHandler;
|
||||||
Thread.ThreadState.ProcessId = ProcessId;
|
Thread.ThreadState.ProcessId = ProcessId;
|
||||||
Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId();
|
Thread.ThreadState.ThreadId = ThreadId;
|
||||||
Thread.ThreadState.Tpidr = Tpidr;
|
Thread.ThreadState.Tpidr = Tpidr;
|
||||||
Thread.ThreadState.X0 = (ulong)ArgsPtr;
|
Thread.ThreadState.X0 = (ulong)ArgsPtr;
|
||||||
Thread.ThreadState.X1 = (ulong)Handle;
|
Thread.ThreadState.X1 = (ulong)Handle;
|
||||||
|
@ -224,7 +228,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
foreach (Executable Exe in Executables)
|
foreach (Executable Exe in Executables)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
|
foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
|
||||||
{
|
{
|
||||||
SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
|
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)
|
private void ThreadFinished(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is AThread Thread)
|
if (sender is AThread Thread)
|
||||||
{
|
{
|
||||||
TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _);
|
Logging.Info($"Thread {Thread.ThreadId} exiting...");
|
||||||
|
|
||||||
Ns.Os.IdGen.DeleteId(Thread.ThreadId);
|
TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
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();
|
Scheduler.Dispose();
|
||||||
|
SvcHandler.Dispose();
|
||||||
|
Memory.Dispose();
|
||||||
|
|
||||||
|
Logging.Info($"Process {ProcessId} exiting...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
class ServiceCtx
|
class ServiceCtx
|
||||||
{
|
{
|
||||||
public Switch Ns { get; private set; }
|
public Switch Ns { get; private set; }
|
||||||
|
public Process Process { get; private set; }
|
||||||
public AMemory Memory { get; private set; }
|
public AMemory Memory { get; private set; }
|
||||||
public HSession Session { get; private set; }
|
public HSession Session { get; private set; }
|
||||||
public IpcMessage Request { get; private set; }
|
public IpcMessage Request { get; private set; }
|
||||||
|
@ -17,6 +18,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
public ServiceCtx(
|
public ServiceCtx(
|
||||||
Switch Ns,
|
Switch Ns,
|
||||||
|
Process Process,
|
||||||
AMemory Memory,
|
AMemory Memory,
|
||||||
HSession Session,
|
HSession Session,
|
||||||
IpcMessage Request,
|
IpcMessage Request,
|
||||||
|
@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
BinaryWriter ResponseData)
|
BinaryWriter ResponseData)
|
||||||
{
|
{
|
||||||
this.Ns = Ns;
|
this.Ns = Ns;
|
||||||
|
this.Process = Process;
|
||||||
this.Memory = Memory;
|
this.Memory = Memory;
|
||||||
this.Session = Session;
|
this.Session = Session;
|
||||||
this.Request = Request;
|
this.Request = Request;
|
||||||
|
|
109
Ryujinx.Core/OsHle/ServiceMgr.cs
Normal file
109
Ryujinx.Core/OsHle/ServiceMgr.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -139,7 +139,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
|
|
||||||
public long RegisterBufferEvent(ServiceCtx Context)
|
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);
|
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||||
|
|
||||||
public long QuerySystemEvent(ServiceCtx Context)
|
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);
|
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||||
|
|
||||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
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>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
{
|
{
|
||||||
{ 0, GetSharedMemoryHandle }
|
{ 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -32,9 +31,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||||
|
|
||||||
public long CreateAppletResource(ServiceCtx Context)
|
public long CreateAppletResource(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
HSharedMem HidHndData = Context.Ns.Os.Handles.GetData<HSharedMem>(Context.Ns.Os.HidHandle);
|
MakeObject(Context, new IAppletResource(Context.Ns.Os.HidSharedMem));
|
||||||
|
|
||||||
MakeObject(Context, new IAppletResource(HidHndData));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
12
Ryujinx.Core/OsHle/Services/Nv/NvFd.cs
Normal file
12
Ryujinx.Core/OsHle/Services/Nv/NvFd.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
Normal file
12
Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using Ryujinx.Core.OsHle.Utilities;
|
using Ryujinx.Core.OsHle.Utilities;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
|
@ -12,41 +11,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
{
|
{
|
||||||
private delegate long ServiceProcessIoctl(ServiceCtx Context);
|
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;
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => 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()
|
public ServiceNvDrv()
|
||||||
{
|
{
|
||||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
@ -58,15 +33,50 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
{ 4, QueryEvent },
|
{ 4, QueryEvent },
|
||||||
{ 8, SetClientPid },
|
{ 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;
|
long NamePtr = Context.Request.SendBuff[0].Position;
|
||||||
|
|
||||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
|
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(Fd);
|
||||||
Context.ResponseData.Write(0);
|
Context.ResponseData.Write(0);
|
||||||
|
@ -74,12 +84,12 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long Ioctl(ServiceCtx Context)
|
public long Ioctl(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
int Fd = Context.RequestData.ReadInt32();
|
int Fd = Context.RequestData.ReadInt32();
|
||||||
int Cmd = Context.RequestData.ReadInt32() & 0xffff;
|
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();
|
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();
|
int Fd = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
Context.Ns.Os.Fds.Delete(Fd);
|
Fds.Delete(Fd);
|
||||||
|
|
||||||
Context.ResponseData.Write(0);
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long Initialize(ServiceCtx Context)
|
public long Initialize(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long TransferMemSize = Context.RequestData.ReadInt64();
|
long TransferMemSize = Context.RequestData.ReadInt64();
|
||||||
int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
|
int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
|
||||||
|
@ -116,7 +126,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long QueryEvent(ServiceCtx Context)
|
public long QueryEvent(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
int Fd = Context.RequestData.ReadInt32();
|
int Fd = Context.RequestData.ReadInt32();
|
||||||
int EventId = Context.RequestData.ReadInt32();
|
int EventId = Context.RequestData.ReadInt32();
|
||||||
|
@ -128,7 +138,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long SetClientPid(ServiceCtx Context)
|
public long SetClientPid(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Pid = Context.RequestData.ReadInt64();
|
long Pid = Context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
@ -137,7 +147,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuAsIoctlBindChannel(ServiceCtx Context)
|
private long NvGpuAsIoctlBindChannel(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -146,7 +156,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
|
private long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -172,7 +182,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
|
private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -186,18 +196,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
long MapSize = Reader.ReadInt64();
|
long MapSize = Reader.ReadInt64();
|
||||||
long Offset = Reader.ReadInt64();
|
long Offset = Reader.ReadInt64();
|
||||||
|
|
||||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
if (Handle == 0)
|
||||||
|
|
||||||
if (NvMap != null)
|
|
||||||
{
|
{
|
||||||
if ((Flags & 1) != 0)
|
//Handle 0 is valid here, but it refers to something else.
|
||||||
{
|
//TODO: Figure out what, for now just return success.
|
||||||
Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size);
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||||
Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size);
|
|
||||||
}
|
if (Map == null)
|
||||||
|
{
|
||||||
|
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);
|
Context.Memory.WriteInt64(Position + 0x20, Offset);
|
||||||
|
@ -205,7 +226,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
|
private long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -235,7 +256,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
|
private long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -252,7 +273,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
|
private long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -267,7 +288,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvHostIoctlCtrlEventWait(ServiceCtx Context)
|
private long NvHostIoctlCtrlEventWait(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -283,7 +304,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
|
private long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -292,7 +313,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
|
private long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -312,7 +333,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
|
private long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -374,7 +395,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
|
private long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -388,7 +409,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
|
private long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -398,14 +419,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelSetUserData(ServiceCtx Context)
|
private long NvMapIoctlChannelSetUserData(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
|
private long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -414,7 +435,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
|
private long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -453,7 +474,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
|
private long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -465,7 +486,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelZcullBind(ServiceCtx Context)
|
private long NvMapIoctlChannelZcullBind(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -478,7 +499,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
|
private long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -492,7 +513,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelSetPriority(ServiceCtx Context)
|
private long NvMapIoctlChannelSetPriority(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -501,7 +522,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
|
private long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -521,47 +542,46 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIocCreate(ServiceCtx Context)
|
private long NvMapIocCreate(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
int Size = Context.Memory.ReadInt32(Position);
|
int Size = Context.Memory.ReadInt32(Position);
|
||||||
|
|
||||||
int Id = Context.Ns.Os.NvMapIds.GenerateId();
|
NvMap Map = new NvMap() { Size = Size };
|
||||||
|
|
||||||
int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size));
|
Map.Handle = NvMaps.Add(Map);
|
||||||
|
|
||||||
Context.Memory.WriteInt32(Position + 4, Handle);
|
Map.Id = NvMapsById.Add(Map);
|
||||||
|
|
||||||
Logging.Info($"NvMap {Id} created with size {Size:x8}!");
|
Context.Memory.WriteInt32(Position + 4, Map.Handle);
|
||||||
|
|
||||||
|
Logging.Info($"NvMap {Map.Id} created with size {Size:x8}!");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIocFromId(ServiceCtx Context)
|
private long NvMapIocFromId(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
int Id = Context.Memory.ReadInt32(Position);
|
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)
|
Logging.Warn($"Trying to use invalid NvMap Id {Id}!");
|
||||||
{
|
|
||||||
Handle = KV.Key;
|
return -1; //TODO: Corrent error code.
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.Memory.WriteInt32(Position + 4, Handle);
|
Context.Memory.WriteInt32(Position + 4, Map.Handle);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIocAlloc(ServiceCtx Context)
|
private long NvMapIocAlloc(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -574,38 +594,49 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
byte Kind = (byte)Reader.ReadInt64();
|
byte Kind = (byte)Reader.ReadInt64();
|
||||||
long Addr = 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;
|
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||||
NvMap.Align = Align;
|
|
||||||
NvMap.Kind = Kind;
|
return -1; //TODO: Corrent error code.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map.Address = Addr;
|
||||||
|
Map.Align = Align;
|
||||||
|
Map.Kind = Kind;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIocFree(ServiceCtx Context)
|
private long NvMapIocFree(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||||
MemWriter Writer = new MemWriter(Context.Memory, Position + 8);
|
MemWriter Writer = new MemWriter(Context.Memory, Position + 8);
|
||||||
|
|
||||||
int Handle = Reader.ReadInt32();
|
int Handle = Reader.ReadInt32();
|
||||||
int Padding = 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.WriteInt64(0);
|
||||||
Writer.WriteInt32(NvMap.Size);
|
Writer.WriteInt32(Map.Size);
|
||||||
Writer.WriteInt32(0);
|
Writer.WriteInt32(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIocParam(ServiceCtx Context)
|
private long NvMapIocParam(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
|
@ -614,16 +645,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
int Handle = Reader.ReadInt32();
|
int Handle = Reader.ReadInt32();
|
||||||
int Param = 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;
|
int Response = 0;
|
||||||
|
|
||||||
switch (Param)
|
switch (Param)
|
||||||
{
|
{
|
||||||
case 1: Response = NvMap.Size; break;
|
case 1: Response = Map.Size; break;
|
||||||
case 2: Response = NvMap.Align; break;
|
case 2: Response = Map.Align; break;
|
||||||
case 4: Response = 0x40000000; break;
|
case 4: Response = 0x40000000; break;
|
||||||
case 5: Response = NvMap.Kind; break;
|
case 5: Response = Map.Kind; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.Memory.WriteInt32(Position + 8, Response);
|
Context.Memory.WriteInt32(Position + 8, Response);
|
||||||
|
@ -631,17 +669,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long NvMapIocGetId(ServiceCtx Context)
|
private long NvMapIocGetId(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
long Position = Context.Request.GetSendBuffPtr();
|
long Position = Context.Request.GetSendBuffPtr();
|
||||||
|
|
||||||
int Handle = Context.Memory.ReadInt32(Position + 4);
|
int Handle = Context.Memory.ReadInt32(Position + 4);
|
||||||
|
|
||||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||||
|
|
||||||
Context.Memory.WriteInt32(Position, NvMap.Id);
|
if (Map == null)
|
||||||
|
{
|
||||||
|
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||||
|
|
||||||
|
return -1; //TODO: Corrent error code.
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.Memory.WriteInt32(Position, Map.Id);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NvMap GetNvMap(int Handle)
|
||||||
|
{
|
||||||
|
return NvMaps.GetData<NvMap>(Handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,13 +9,13 @@ namespace Ryujinx.Core.OsHle.IpcServices
|
||||||
{
|
{
|
||||||
if (Context.Session is HDomain Dom)
|
if (Context.Session is HDomain Dom)
|
||||||
{
|
{
|
||||||
Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj));
|
Context.Response.ResponseObjIds.Add(Dom.Add(Obj));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HSessionObj HndData = new HSessionObj(Context.Session, Obj);
|
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);
|
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
Context.ResponseData.Write(1); //Loaded
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long GetFontSize(ServiceCtx Context)
|
public long GetFontSize(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
Context.ResponseData.Write(Horizon.FontSize);
|
Context.ResponseData.Write(Horizon.FontSize);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long GetSharedMemoryAddressOffset(ServiceCtx Context)
|
public long GetSharedMemoryAddressOffset(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
Context.ResponseData.Write(0);
|
Context.ResponseData.Write(0);
|
||||||
|
|
||||||
return 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -55,9 +55,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
|
||||||
return 0;
|
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);
|
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.Core.OsHle
|
namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
{
|
{
|
||||||
class Display
|
class Display
|
||||||
{
|
{
|
|
@ -15,6 +15,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
|
|
||||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
|
private IdDictionary Displays;
|
||||||
|
|
||||||
public IApplicationDisplayService()
|
public IApplicationDisplayService()
|
||||||
{
|
{
|
||||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
|
@ -28,14 +30,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
{ 2020, OpenLayer },
|
{ 2020, OpenLayer },
|
||||||
{ 2021, CloseLayer },
|
{ 2021, CloseLayer },
|
||||||
{ 2030, CreateStrayLayer },
|
{ 2030, CreateStrayLayer },
|
||||||
|
{ 2031, DestroyStrayLayer },
|
||||||
{ 2101, SetLayerScalingMode },
|
{ 2101, SetLayerScalingMode },
|
||||||
{ 5202, GetDisplayVSyncEvent }
|
{ 5202, GetDisplayVSyncEvent }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Displays = new IdDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long GetRelayService(ServiceCtx Context)
|
public long GetRelayService(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
MakeObject(Context, new IHOSBinderDriver());
|
MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +61,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
|
|
||||||
public long GetIndirectDisplayTransactionService(ServiceCtx Context)
|
public long GetIndirectDisplayTransactionService(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
MakeObject(Context, new IHOSBinderDriver());
|
MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +70,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
{
|
{
|
||||||
string Name = GetDisplayName(Context);
|
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);
|
Context.ResponseData.Write(DisplayId);
|
||||||
|
|
||||||
|
@ -76,7 +81,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
{
|
{
|
||||||
int DisplayId = Context.RequestData.ReadInt32();
|
int DisplayId = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
Context.Ns.Os.Displays.Delete(DisplayId);
|
Displays.Delete(DisplayId);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -99,6 +104,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
|
|
||||||
public long CloseLayer(ServiceCtx Context)
|
public long CloseLayer(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
|
long LayerId = Context.RequestData.ReadInt64();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +116,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
|
|
||||||
long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
|
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);
|
byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
|
||||||
|
|
||||||
|
@ -121,6 +128,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long DestroyStrayLayer(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public long SetLayerScalingMode(ServiceCtx Context)
|
public long SetLayerScalingMode(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
int ScalingMode = Context.RequestData.ReadInt32();
|
int ScalingMode = Context.RequestData.ReadInt32();
|
||||||
|
@ -133,7 +145,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
{
|
{
|
||||||
string Name = GetDisplayName(Context);
|
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);
|
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using Ryujinx.Core.OsHle.IpcServices.Android;
|
using Ryujinx.Core.OsHle.IpcServices.Android;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
|
|
||||||
private NvFlinger Flinger;
|
private NvFlinger Flinger;
|
||||||
|
|
||||||
public IHOSBinderDriver()
|
public IHOSBinderDriver(IGalRenderer Renderer)
|
||||||
{
|
{
|
||||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
{
|
{
|
||||||
|
@ -23,7 +24,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
|
||||||
{ 2, GetNativeHandle }
|
{ 2, GetNativeHandle }
|
||||||
};
|
};
|
||||||
|
|
||||||
Flinger = new NvFlinger();
|
Flinger = new NvFlinger(Renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long TransactParcel(ServiceCtx Context)
|
public long TransactParcel(ServiceCtx Context)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.IpcServices.NvServices;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -54,18 +55,27 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
public GbpBuffer Data;
|
public GbpBuffer Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IGalRenderer Renderer;
|
||||||
|
|
||||||
private BufferEntry[] BufferQueue;
|
private BufferEntry[] BufferQueue;
|
||||||
|
|
||||||
private ManualResetEvent WaitBufferFree;
|
private ManualResetEvent WaitBufferFree;
|
||||||
|
|
||||||
|
private object RenderQueueLock;
|
||||||
|
|
||||||
|
private int RenderQueueCount;
|
||||||
|
|
||||||
|
private bool NvFlingerDisposed;
|
||||||
|
|
||||||
private bool KeepRunning;
|
private bool KeepRunning;
|
||||||
|
|
||||||
public NvFlinger()
|
public NvFlinger(IGalRenderer Renderer)
|
||||||
{
|
{
|
||||||
Commands = new Dictionary<(string, int), ServiceProcessParcel>()
|
Commands = new Dictionary<(string, int), ServiceProcessParcel>()
|
||||||
{
|
{
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer },
|
{ ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer },
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer },
|
{ ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer },
|
||||||
|
{ ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer },
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer },
|
{ ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer },
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer },
|
{ ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer },
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery },
|
{ ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery },
|
||||||
|
@ -74,10 +84,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.Renderer = Renderer;
|
||||||
|
|
||||||
BufferQueue = new BufferEntry[0x40];
|
BufferQueue = new BufferEntry[0x40];
|
||||||
|
|
||||||
WaitBufferFree = new ManualResetEvent(false);
|
WaitBufferFree = new ManualResetEvent(false);
|
||||||
|
|
||||||
|
RenderQueueLock = new object();
|
||||||
|
|
||||||
KeepRunning = true;
|
KeepRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +207,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
|
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)
|
private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader)
|
||||||
{
|
{
|
||||||
//TODO: Errors.
|
//TODO: Errors.
|
||||||
|
@ -266,7 +285,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
|
|
||||||
long FbSize = (uint)FbWidth * FbHeight * 4;
|
long FbSize = (uint)FbWidth * FbHeight * 4;
|
||||||
|
|
||||||
HNvMap NvMap = GetNvMap(Context, Slot);
|
NvMap NvMap = GetNvMap(Context, Slot);
|
||||||
|
|
||||||
if ((ulong)(NvMap.Address + FbSize) > AMemoryMgr.AddrSize)
|
if ((ulong)(NvMap.Address + FbSize) > AMemoryMgr.AddrSize)
|
||||||
{
|
{
|
||||||
|
@ -330,7 +349,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
Rotate = -MathF.PI * 0.5f;
|
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()
|
Context.Ns.Gpu.Renderer.QueueAction(delegate()
|
||||||
{
|
{
|
||||||
|
@ -346,6 +375,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
|
|
||||||
BufferQueue[Slot].State = BufferState.Free;
|
BufferQueue[Slot].State = BufferState.Free;
|
||||||
|
|
||||||
|
Interlocked.Decrement(ref RenderQueueCount);
|
||||||
|
|
||||||
lock (WaitBufferFree)
|
lock (WaitBufferFree)
|
||||||
{
|
{
|
||||||
WaitBufferFree.Set();
|
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);
|
int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
|
||||||
|
|
||||||
|
@ -366,7 +397,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
NvMapHandle = BitConverter.ToInt32(RawValue, 0);
|
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)
|
private int GetFreeSlotBlocking(int Width, int Height)
|
||||||
|
@ -432,10 +465,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
|
||||||
Dispose(true);
|
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)
|
lock (WaitBufferFree)
|
||||||
{
|
{
|
||||||
KeepRunning = false;
|
KeepRunning = false;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
using ChocolArm64.Events;
|
using ChocolArm64.Events;
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Core.OsHle.Svc
|
namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
partial class SvcHandler
|
partial class SvcHandler : IDisposable
|
||||||
{
|
{
|
||||||
private delegate void SvcFunc(AThreadState ThreadState);
|
private delegate void SvcFunc(AThreadState ThreadState);
|
||||||
|
|
||||||
|
@ -16,10 +17,12 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
private Process Process;
|
private Process Process;
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
|
|
||||||
private static Random Rng;
|
private HashSet<(HSharedMem, long)> MappedSharedMems;
|
||||||
|
|
||||||
private ulong CurrentHeapSize;
|
private ulong CurrentHeapSize;
|
||||||
|
|
||||||
|
private static Random Rng;
|
||||||
|
|
||||||
public SvcHandler(Switch Ns, Process Process)
|
public SvcHandler(Switch Ns, Process Process)
|
||||||
{
|
{
|
||||||
SvcFuncs = new Dictionary<int, SvcFunc>()
|
SvcFuncs = new Dictionary<int, SvcFunc>()
|
||||||
|
@ -32,6 +35,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{ 0x07, SvcExitProcess },
|
{ 0x07, SvcExitProcess },
|
||||||
{ 0x08, SvcCreateThread },
|
{ 0x08, SvcCreateThread },
|
||||||
{ 0x09, SvcStartThread },
|
{ 0x09, SvcStartThread },
|
||||||
|
{ 0x0a, SvcExitThread },
|
||||||
{ 0x0b, SvcSleepThread },
|
{ 0x0b, SvcSleepThread },
|
||||||
{ 0x0c, SvcGetThreadPriority },
|
{ 0x0c, SvcGetThreadPriority },
|
||||||
{ 0x0d, SvcSetThreadPriority },
|
{ 0x0d, SvcSetThreadPriority },
|
||||||
|
@ -60,6 +64,8 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
this.Ns = Ns;
|
this.Ns = Ns;
|
||||||
this.Process = Process;
|
this.Process = Process;
|
||||||
this.Memory = Process.Memory;
|
this.Memory = Process.Memory;
|
||||||
|
|
||||||
|
MappedSharedMems = new HashSet<(HSharedMem, long)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static SvcHandler()
|
static SvcHandler()
|
||||||
|
@ -84,5 +90,26 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
throw new NotImplementedException(e.Id.ToString("x4"));
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -165,7 +165,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HSharedMem SharedMem = Ns.Os.Handles.GetData<HSharedMem>(Handle);
|
HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
|
||||||
|
|
||||||
if (SharedMem != null)
|
if (SharedMem != null)
|
||||||
{
|
{
|
||||||
|
@ -175,7 +175,12 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
|
|
||||||
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
|
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
|
||||||
|
|
||||||
SharedMem.AddVirtualPosition(Src);
|
lock (MappedSharedMems)
|
||||||
|
{
|
||||||
|
MappedSharedMems.Add((SharedMem, Src));
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMem.AddVirtualPosition(Memory, Src);
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
@ -198,12 +203,19 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
return;
|
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);
|
Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory);
|
||||||
|
|
||||||
|
SharedMem.RemoveVirtualPosition(Memory, Src);
|
||||||
|
|
||||||
|
lock (MappedSharedMems)
|
||||||
|
{
|
||||||
|
MappedSharedMems.Remove((SharedMem, Src));
|
||||||
|
}
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,12 +241,12 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
|
|
||||||
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
|
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
|
||||||
|
|
||||||
HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
|
HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
|
||||||
|
|
||||||
int Handle = Ns.Os.Handles.GenerateId(HndData);
|
ulong Handle = (ulong)Process.HandleTable.OpenHandle(TMem);
|
||||||
|
|
||||||
ThreadState.X1 = (ulong)Handle;
|
|
||||||
ThreadState.X0 = 0;
|
ThreadState.X0 = 0;
|
||||||
|
ThreadState.X1 = Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsValidPosition(long Position)
|
private static bool IsValidPosition(long Position)
|
||||||
|
|
|
@ -3,7 +3,6 @@ using ChocolArm64.State;
|
||||||
using Ryujinx.Core.OsHle.Exceptions;
|
using Ryujinx.Core.OsHle.Exceptions;
|
||||||
using Ryujinx.Core.OsHle.Handles;
|
using Ryujinx.Core.OsHle.Handles;
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using Ryujinx.Core.OsHle.IpcServices;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -35,7 +34,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
int Handle = (int)ThreadState.X0;
|
int Handle = (int)ThreadState.X0;
|
||||||
|
|
||||||
Ns.Os.CloseHandle(Handle);
|
Process.HandleTable.CloseHandle(Handle);
|
||||||
|
|
||||||
ThreadState.X0 = 0;
|
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
|
//TODO: Validate that app has perms to access the service, and that the service
|
||||||
//actually exists, return error codes otherwise.
|
//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.X0 = 0;
|
||||||
|
ThreadState.X1 = Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SvcSendSyncRequest(AThreadState ThreadState)
|
private void SvcSendSyncRequest(AThreadState ThreadState)
|
||||||
|
@ -119,13 +120,21 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
|
|
||||||
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
|
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);
|
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
|
||||||
|
|
||||||
if (Session != null)
|
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);
|
byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
int Handle = (int)ThreadState.X0;
|
int Handle = (int)ThreadState.X0;
|
||||||
|
|
||||||
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
|
HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
|
||||||
|
|
||||||
if (Thread != null)
|
if (Thread != null)
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,13 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
//TODO: Error codes.
|
//TODO: Error codes.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SvcExitThread(AThreadState ThreadState)
|
||||||
|
{
|
||||||
|
HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||||
|
|
||||||
|
CurrThread.Thread.StopExecution();
|
||||||
|
}
|
||||||
|
|
||||||
private void SvcSleepThread(AThreadState ThreadState)
|
private void SvcSleepThread(AThreadState ThreadState)
|
||||||
{
|
{
|
||||||
ulong NanoSecs = ThreadState.X0;
|
ulong NanoSecs = ThreadState.X0;
|
||||||
|
@ -71,7 +78,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
int Handle = (int)ThreadState.X1;
|
int Handle = (int)ThreadState.X1;
|
||||||
|
|
||||||
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
|
HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
|
||||||
|
|
||||||
if (Thread != null)
|
if (Thread != null)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +94,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
int Handle = (int)ThreadState.X1;
|
int Handle = (int)ThreadState.X1;
|
||||||
int Prio = (int)ThreadState.X0;
|
int Prio = (int)ThreadState.X0;
|
||||||
|
|
||||||
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
|
HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
|
||||||
|
|
||||||
if (Thread != null)
|
if (Thread != null)
|
||||||
{
|
{
|
||||||
|
@ -110,7 +117,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
{
|
{
|
||||||
int Handle = (int)ThreadState.X0;
|
int Handle = (int)ThreadState.X0;
|
||||||
|
|
||||||
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
|
HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
|
||||||
|
|
||||||
if (Thread != null)
|
if (Thread != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
long MutexAddress = (long)ThreadState.X1;
|
long MutexAddress = (long)ThreadState.X1;
|
||||||
int RequestingThreadHandle = (int)ThreadState.X2;
|
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);
|
Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
int ThreadHandle = (int)ThreadState.X2;
|
int ThreadHandle = (int)ThreadState.X2;
|
||||||
long Timeout = (long)ThreadState.X3;
|
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);
|
Mutex M = new Mutex(Process, MutexAddress, ThreadHandle);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,3 @@
|
||||||
using ChocolArm64.Memory;
|
|
||||||
using Ryujinx.Core.Input;
|
using Ryujinx.Core.Input;
|
||||||
using Ryujinx.Core.OsHle;
|
using Ryujinx.Core.OsHle;
|
||||||
using Ryujinx.Core.Settings;
|
using Ryujinx.Core.Settings;
|
||||||
|
@ -10,8 +9,6 @@ namespace Ryujinx.Core
|
||||||
{
|
{
|
||||||
public class Switch : IDisposable
|
public class Switch : IDisposable
|
||||||
{
|
{
|
||||||
internal AMemory Memory { get; private set; }
|
|
||||||
|
|
||||||
internal NsGpu Gpu { get; private set; }
|
internal NsGpu Gpu { get; private set; }
|
||||||
internal Horizon Os { get; private set; }
|
internal Horizon Os { get; private set; }
|
||||||
internal VirtualFs VFs { get; private set; }
|
internal VirtualFs VFs { get; private set; }
|
||||||
|
@ -24,13 +21,11 @@ namespace Ryujinx.Core
|
||||||
|
|
||||||
public Switch(IGalRenderer Renderer)
|
public Switch(IGalRenderer Renderer)
|
||||||
{
|
{
|
||||||
Memory = new AMemory();
|
|
||||||
|
|
||||||
Gpu = new NsGpu(Renderer);
|
Gpu = new NsGpu(Renderer);
|
||||||
|
|
||||||
VFs = new VirtualFs();
|
VFs = new VirtualFs();
|
||||||
|
|
||||||
Hid = new Hid(Memory);
|
Hid = new Hid();
|
||||||
|
|
||||||
Statistics = new PerformanceStatistics();
|
Statistics = new PerformanceStatistics();
|
||||||
|
|
||||||
|
@ -42,11 +37,6 @@ namespace Ryujinx.Core
|
||||||
Settings = new SetSys();
|
Settings = new SetSys();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FinalizeAllProcesses()
|
|
||||||
{
|
|
||||||
Os.FinalizeAllProcesses();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
||||||
{
|
{
|
||||||
Os.LoadCart(ExeFsDir, RomFsFile);
|
Os.LoadCart(ExeFsDir, RomFsFile);
|
||||||
|
@ -67,12 +57,11 @@ namespace Ryujinx.Core
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool Disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
Memory.Dispose();
|
Os.Dispose();
|
||||||
|
|
||||||
VFs.Dispose();
|
VFs.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void RunActions();
|
void RunActions();
|
||||||
|
|
||||||
void InitializeFrameBuffer();
|
void InitializeFrameBuffer();
|
||||||
|
void ResetFrameBuffer();
|
||||||
void Render();
|
void Render();
|
||||||
void SetWindowSize(int Width, int Height);
|
void SetWindowSize(int Width, int Height);
|
||||||
void SetFrameBuffer(
|
void SetFrameBuffer(
|
||||||
|
|
|
@ -24,6 +24,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private byte* FbPtr;
|
private byte* FbPtr;
|
||||||
|
|
||||||
|
private object FbPtrLock;
|
||||||
|
|
||||||
public FrameBuffer(int Width, int Height)
|
public FrameBuffer(int Width, int Height)
|
||||||
{
|
{
|
||||||
if (Width < 0)
|
if (Width < 0)
|
||||||
|
@ -36,6 +38,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new ArgumentOutOfRangeException(nameof(Height));
|
throw new ArgumentOutOfRangeException(nameof(Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FbPtrLock = new object();
|
||||||
|
|
||||||
TexWidth = Width;
|
TexWidth = Width;
|
||||||
TexHeight = Height;
|
TexHeight = Height;
|
||||||
|
|
||||||
|
@ -152,7 +156,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new ArgumentOutOfRangeException(nameof(Height));
|
throw new ArgumentOutOfRangeException(nameof(Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
FbPtr = Fb;
|
lock (FbPtrLock)
|
||||||
|
{
|
||||||
|
FbPtr = Fb;
|
||||||
|
}
|
||||||
|
|
||||||
if (Width != TexWidth ||
|
if (Width != TexWidth ||
|
||||||
Height != TexHeight)
|
Height != TexHeight)
|
||||||
|
@ -178,17 +185,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.Uniform2(OffsetUniformLocation, Offs);
|
GL.Uniform2(OffsetUniformLocation, Offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
lock (FbPtrLock)
|
||||||
|
{
|
||||||
|
FbPtr = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Render()
|
public void Render()
|
||||||
{
|
{
|
||||||
if (FbPtr == null)
|
lock (FbPtrLock)
|
||||||
{
|
{
|
||||||
return;
|
if (FbPtr == null)
|
||||||
}
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int Y = 0; Y < TexHeight; Y++)
|
for (int Y = 0; Y < TexHeight; Y++)
|
||||||
for (int X = 0; X < TexWidth; X++)
|
for (int X = 0; X < TexWidth; X++)
|
||||||
{
|
{
|
||||||
Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
|
Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
|
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
|
||||||
|
|
|
@ -43,6 +43,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
FbRenderer = new FrameBuffer(1280, 720);
|
FbRenderer = new FrameBuffer(1280, 720);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ResetFrameBuffer()
|
||||||
|
{
|
||||||
|
FbRenderer.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
public void QueueAction(Action ActionMthd)
|
public void QueueAction(Action ActionMthd)
|
||||||
{
|
{
|
||||||
ActionsQueue.Enqueue(ActionMthd);
|
ActionsQueue.Enqueue(ActionMthd);
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
ATranslator Translator = new ATranslator();
|
ATranslator Translator = new ATranslator();
|
||||||
Memory = new AMemory();
|
Memory = new AMemory();
|
||||||
Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
|
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]
|
[TearDown]
|
||||||
|
|
Loading…
Reference in a new issue