1
1
mirror of https://github.com/ryujinx-mirror/ryujinx.git synced 2025-09-19 11:07:53 -05:00

Made initial implementation of the thread scheduler, refactor Svc to avoid passing many arguments

This commit is contained in:
gdkchan
2018-02-13 23:43:08 -03:00
parent 598d1fd3ae
commit f68696dc4a
19 changed files with 740 additions and 252 deletions

View File

@@ -7,55 +7,50 @@ namespace Ryujinx.OsHle.Svc
{
partial class SvcHandler
{
private delegate void SvcFunc(Switch Ns, ARegisters Registers, AMemory Memory);
private delegate void SvcFunc(ARegisters Registers);
private Dictionary<int, SvcFunc> SvcFuncs = new Dictionary<int, SvcFunc>()
{
{ 0x01, SvcSetHeapSize },
{ 0x03, SvcSetMemoryAttribute },
{ 0x04, SvcMapMemory },
{ 0x06, SvcQueryMemory },
{ 0x08, SvcCreateThread },
{ 0x09, SvcStartThread },
{ 0x0b, SvcSleepThread },
{ 0x0c, SvcGetThreadPriority },
{ 0x13, SvcMapSharedMemory },
{ 0x14, SvcUnmapSharedMemory },
{ 0x15, SvcCreateTransferMemory },
{ 0x16, SvcCloseHandle },
{ 0x17, SvcResetSignal },
{ 0x18, SvcWaitSynchronization },
{ 0x1a, SvcArbitrateLock },
{ 0x1b, SvcArbitrateUnlock },
{ 0x1c, SvcWaitProcessWideKeyAtomic },
{ 0x1d, SvcSignalProcessWideKey },
{ 0x1e, SvcGetSystemTick },
{ 0x1f, SvcConnectToNamedPort },
{ 0x21, SvcSendSyncRequest },
{ 0x22, SvcSendSyncRequestWithUserBuffer },
{ 0x26, SvcBreak },
{ 0x27, SvcOutputDebugString },
{ 0x29, SvcGetInfo }
};
enum SvcResult
{
Success = 0,
ErrBadHandle = 0xe401,
ErrTimeout = 0xea01,
ErrBadInfo = 0xf001,
ErrBadIpcReq = 0xf601
}
private Dictionary<int, SvcFunc> SvcFuncs;
private Switch Ns;
private Process Process;
private AMemory Memory;
private static Random Rng;
public SvcHandler(Switch Ns, AMemory Memory)
public SvcHandler(Switch Ns, Process Process)
{
this.Ns = Ns;
this.Memory = Memory;
SvcFuncs = new Dictionary<int, SvcFunc>()
{
{ 0x01, SvcSetHeapSize },
{ 0x03, SvcSetMemoryAttribute },
{ 0x04, SvcMapMemory },
{ 0x06, SvcQueryMemory },
{ 0x08, SvcCreateThread },
{ 0x09, SvcStartThread },
{ 0x0b, SvcSleepThread },
{ 0x0c, SvcGetThreadPriority },
{ 0x13, SvcMapSharedMemory },
{ 0x14, SvcUnmapSharedMemory },
{ 0x15, SvcCreateTransferMemory },
{ 0x16, SvcCloseHandle },
{ 0x17, SvcResetSignal },
{ 0x18, SvcWaitSynchronization },
{ 0x1a, SvcArbitrateLock },
{ 0x1b, SvcArbitrateUnlock },
{ 0x1c, SvcWaitProcessWideKeyAtomic },
{ 0x1d, SvcSignalProcessWideKey },
{ 0x1e, SvcGetSystemTick },
{ 0x1f, SvcConnectToNamedPort },
{ 0x21, SvcSendSyncRequest },
{ 0x22, SvcSendSyncRequestWithUserBuffer },
{ 0x26, SvcBreak },
{ 0x27, SvcOutputDebugString },
{ 0x29, SvcGetInfo }
};
this.Ns = Ns;
this.Process = Process;
this.Memory = Process.Memory;
}
static SvcHandler()
@@ -69,9 +64,11 @@ namespace Ryujinx.OsHle.Svc
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
{
Logging.Trace($"{Func.Method.Name} called.");
Func(Ns, Registers, Memory);
Logging.Trace($"{Func.Method.Name} ended.");
Logging.Trace($"(Thread {Registers.ThreadId}) {Func.Method.Name} called.");
Func(Registers);
Logging.Trace($"(Thread {Registers.ThreadId}) {Func.Method.Name} ended.");
}
else
{

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.OsHle.Svc
{
partial class SvcHandler
{
private static void SvcSetHeapSize(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcSetHeapSize(ARegisters Registers)
{
uint Size = (uint)Registers.X1;
@@ -16,7 +16,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X1 = (ulong)Memory.Manager.HeapAddr;
}
private static void SvcSetMemoryAttribute(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcSetMemoryAttribute(ARegisters Registers)
{
long Position = (long)Registers.X0;
long Size = (long)Registers.X1;
@@ -28,7 +28,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcMapMemory(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcMapMemory(ARegisters Registers)
{
long Dst = (long)Registers.X0;
long Src = (long)Registers.X1;
@@ -39,7 +39,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcQueryMemory(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcQueryMemory(ARegisters Registers)
{
long InfoPtr = (long)Registers.X0;
long Position = (long)Registers.X2;
@@ -63,7 +63,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X1 = 0;
}
private static void SvcMapSharedMemory(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcMapSharedMemory(ARegisters Registers)
{
int Handle = (int)Registers.X0;
long Position = (long)Registers.X1;
@@ -87,7 +87,7 @@ namespace Ryujinx.OsHle.Svc
//TODO: Error codes.
}
private static void SvcUnmapSharedMemory(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcUnmapSharedMemory(ARegisters Registers)
{
int Handle = (int)Registers.X0;
long Position = (long)Registers.X1;
@@ -103,7 +103,7 @@ namespace Ryujinx.OsHle.Svc
//TODO: Error codes.
}
private static void SvcCreateTransferMemory(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcCreateTransferMemory(ARegisters Registers)
{
long Position = (long)Registers.X1;
long Size = (long)Registers.X2;

View File

@@ -0,0 +1,11 @@
namespace Ryujinx.OsHle.Svc
{
enum SvcResult
{
Success = 0,
ErrBadHandle = 0xe401,
ErrTimeout = 0xea01,
ErrBadInfo = 0xf001,
ErrBadIpcReq = 0xf601
}
}

View File

@@ -1,5 +1,6 @@
using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.OsHle.Exceptions;
using Ryujinx.OsHle.Handles;
using Ryujinx.OsHle.Ipc;
using System;
@@ -8,7 +9,7 @@ namespace Ryujinx.OsHle.Svc
{
partial class SvcHandler
{
private static void SvcCloseHandle(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcCloseHandle(ARegisters Registers)
{
int Handle = (int)Registers.X0;
@@ -17,7 +18,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcResetSignal(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcResetSignal(ARegisters Registers)
{
int Handle = (int)Registers.X0;
@@ -26,7 +27,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcWaitSynchronization(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcWaitSynchronization(ARegisters Registers)
{
long HandlesPtr = (long)Registers.X0;
int HandlesCount = (int)Registers.X2;
@@ -34,15 +35,26 @@ namespace Ryujinx.OsHle.Svc
//TODO: Implement events.
//Logging.Info($"SvcWaitSynchronization Thread {Registers.ThreadId}");
if (Process.TryGetThread(Registers.Tpidr, out HThread Thread))
{
Process.Scheduler.Yield(Thread);
}
else
{
Logging.Error($"Thread with TPIDR_EL0 0x{Registers.Tpidr:x16} not found!");
}
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcGetSystemTick(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcGetSystemTick(ARegisters Registers)
{
Registers.X0 = (ulong)Registers.CntpctEl0;
}
private static void SvcConnectToNamedPort(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcConnectToNamedPort(ARegisters Registers)
{
long StackPtr = (long)Registers.X0;
long NamePtr = (long)Registers.X1;
@@ -58,23 +70,23 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcSendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcSendSyncRequest(ARegisters Registers)
{
SendSyncRequest(Ns, Registers, Memory, false);
SendSyncRequest(Registers, false);
}
private static void SvcSendSyncRequestWithUserBuffer(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcSendSyncRequestWithUserBuffer(ARegisters Registers)
{
SendSyncRequest(Ns, Registers, Memory, true);
SendSyncRequest(Registers, true);
}
private static void SendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory, bool IsUser)
private void SendSyncRequest(ARegisters Registers, bool UserBuffer)
{
long CmdPtr = Registers.Tpidr;
long Size = 0x100;
int Handle = 0;
if (IsUser)
if (UserBuffer)
{
CmdPtr = (long)Registers.X0;
Size = (long)Registers.X1;
@@ -105,16 +117,16 @@ namespace Ryujinx.OsHle.Svc
}
}
private static void SvcBreak(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcBreak(ARegisters Registers)
{
long Reason = (long)Registers.X0;
long Unknown = (long)Registers.X1;
long Info = (long)Registers.X2;
throw new Exception($"SvcBreak: {Reason} {Unknown} {Info}");
throw new GuestBrokeExecutionException();
}
private static void SvcOutputDebugString(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcOutputDebugString(ARegisters Registers)
{
long Position = (long)Registers.X0;
long Size = (long)Registers.X1;
@@ -126,7 +138,7 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcGetInfo(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcGetInfo(ARegisters Registers)
{
long StackPtr = (long)Registers.X0;
int InfoType = (int)Registers.X1;
@@ -148,8 +160,8 @@ namespace Ryujinx.OsHle.Svc
case 3: Registers.X1 = GetMapRegionSize(); break;
case 4: Registers.X1 = GetHeapRegionBaseAddr(); break;
case 5: Registers.X1 = GetHeapRegionSize(); break;
case 6: Registers.X1 = GetTotalMem(Memory); break;
case 7: Registers.X1 = GetUsedMem(Memory); break;
case 6: Registers.X1 = GetTotalMem(); break;
case 7: Registers.X1 = GetUsedMem(); break;
case 11: Registers.X1 = GetRnd64(); break;
case 12: Registers.X1 = GetAddrSpaceBaseAddr(); break;
case 13: Registers.X1 = GetAddrSpaceSize(); break;
@@ -162,47 +174,47 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static ulong GetTotalMem(AMemory Memory)
private ulong GetTotalMem()
{
return (ulong)Memory.Manager.GetTotalMemorySize();
}
private static ulong GetUsedMem(AMemory Memory)
private ulong GetUsedMem()
{
return (ulong)Memory.Manager.GetUsedMemorySize();
}
private static ulong GetRnd64()
private ulong GetRnd64()
{
return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
}
private static ulong GetAddrSpaceBaseAddr()
private ulong GetAddrSpaceBaseAddr()
{
return 0x08000000;
}
private static ulong GetAddrSpaceSize()
private ulong GetAddrSpaceSize()
{
return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr();
}
private static ulong GetMapRegionBaseAddr()
private ulong GetMapRegionBaseAddr()
{
return 0x80000000;
}
private static ulong GetMapRegionSize()
private ulong GetMapRegionSize()
{
return 0x40000000;
}
private static ulong GetHeapRegionBaseAddr()
private ulong GetHeapRegionBaseAddr()
{
return GetMapRegionBaseAddr() + GetMapRegionSize();
}
private static ulong GetHeapRegionSize()
private ulong GetHeapRegionSize()
{
return 0x40000000;
}

View File

@@ -1,4 +1,3 @@
using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.OsHle.Handles;
using System.Threading;
@@ -7,7 +6,7 @@ namespace Ryujinx.OsHle.Svc
{
partial class SvcHandler
{
private static void SvcCreateThread(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcCreateThread(ARegisters Registers)
{
long EntryPoint = (long)Registers.X1;
long ArgsPtr = (long)Registers.X2;
@@ -17,12 +16,17 @@ namespace Ryujinx.OsHle.Svc
if (Ns.Os.TryGetProcess(Registers.ProcessId, out Process Process))
{
if (ProcessorId == -2)
{
ProcessorId = 0;
}
int Handle = Process.MakeThread(
EntryPoint,
StackTop,
ArgsPtr,
Priority,
ProcessorId);
ProcessorId);
Registers.X0 = (int)SvcResult.Success;
Registers.X1 = (ulong)Handle;
@@ -31,15 +35,15 @@ namespace Ryujinx.OsHle.Svc
//TODO: Error codes.
}
private static void SvcStartThread(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcStartThread(ARegisters Registers)
{
int Handle = (int)Registers.X0;
HThread HndData = Ns.Os.Handles.GetData<HThread>(Handle);
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
if (HndData != null)
if (Thread != null)
{
HndData.Thread.Execute();
Process.Scheduler.StartThread(Thread);
Registers.X0 = (int)SvcResult.Success;
}
@@ -47,29 +51,31 @@ namespace Ryujinx.OsHle.Svc
//TODO: Error codes.
}
private static void SvcSleepThread(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcSleepThread(ARegisters Registers)
{
ulong NanoSecs = Registers.X0;
if (NanoSecs == 0)
if (Process.TryGetThread(Registers.Tpidr, out HThread CurrThread))
{
Thread.Yield();
Process.Scheduler.Yield(CurrThread);
}
else
{
Thread.Sleep((int)(NanoSecs / 1000000));
Logging.Error($"Thread with TPIDR_EL0 0x{Registers.Tpidr:x16} not found!");
}
Thread.Sleep((int)(NanoSecs / 1000000));
}
private static void SvcGetThreadPriority(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcGetThreadPriority(ARegisters Registers)
{
int Handle = (int)Registers.X1;
HThread HndData = Ns.Os.Handles.GetData<HThread>(Handle);
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
if (HndData != null)
if (Thread != null)
{
Registers.X1 = (ulong)HndData.Thread.Priority;
Registers.X1 = (ulong)Thread.Priority;
Registers.X0 = (int)SvcResult.Success;
}

View File

@@ -1,5 +1,4 @@
using ChocolArm64;
using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.OsHle.Handles;
@@ -7,27 +6,24 @@ namespace Ryujinx.OsHle.Svc
{
partial class SvcHandler
{
private static void SvcArbitrateLock(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcArbitrateLock(ARegisters Registers)
{
int OwnerThreadHandle = (int)Registers.X0;
long MutexAddress = (long)Registers.X1;
int RequestingThreadHandle = (int)Registers.X2;
AThread RequestingThread = Ns.Os.Handles.GetData<HThread>(RequestingThreadHandle).Thread;
HThread RequestingThread = Ns.Os.Handles.GetData<HThread>(RequestingThreadHandle);
Mutex M = new Mutex(Memory, MutexAddress);
Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M);
//FIXME
//M.WaitForLock(RequestingThread, RequestingThreadHandle);
Memory.WriteInt32(MutexAddress, 0);
M.WaitForLock(RequestingThread, RequestingThreadHandle);
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcArbitrateUnlock(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcArbitrateUnlock(ARegisters Registers)
{
long MutexAddress = (long)Registers.X0;
@@ -39,39 +35,36 @@ namespace Ryujinx.OsHle.Svc
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcWaitProcessWideKeyAtomic(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcWaitProcessWideKeyAtomic(ARegisters Registers)
{
long MutexAddress = (long)Registers.X0;
long CondVarAddress = (long)Registers.X1;
int ThreadHandle = (int)Registers.X2;
long Timeout = (long)Registers.X3;
AThread Thread = Ns.Os.Handles.GetData<HThread>(ThreadHandle).Thread;
HThread Thread = Ns.Os.Handles.GetData<HThread>(ThreadHandle);
if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M))
{
M.GiveUpLock(ThreadHandle);
}
CondVar Signal = new CondVar(Memory, CondVarAddress, Timeout);
CondVar Cv = new CondVar(Process, CondVarAddress, Timeout);
Signal = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Signal);
Cv = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Cv);
Signal.WaitForSignal(ThreadHandle);
Cv.WaitForSignal(Thread);
M = new Mutex(Memory, MutexAddress);
M = new Mutex(Process, MutexAddress, ThreadHandle);
M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M);
//FIXME
//M.WaitForLock(Thread, ThreadHandle);
Memory.WriteInt32(MutexAddress, 0);
M.WaitForLock(Thread, ThreadHandle);
Registers.X0 = (int)SvcResult.Success;
}
private static void SvcSignalProcessWideKey(Switch Ns, ARegisters Registers, AMemory Memory)
private void SvcSignalProcessWideKey(ARegisters Registers)
{
long CondVarAddress = (long)Registers.X0;
int Count = (int)Registers.X1;